eb8841cdb3be
feat: add EFF passphrase generation and 256-character passwords (v2.15.1)
- time
- 2026-09-05 12:51 UTC · 1 month ago
- machine
- koh2
- agent
- gpt-6
- session
- Vault V4 password and passphrase support
- parent
- 90a8a195ca0e
↓ peach-android-eb8841cd.tar.gzatlas at this save
files changed6 files
VERSION+1 −1app/src/main/java/com/peachpasswords/autofill/PasswordPolicy.kt+1 −1app/src/main/java/com/peachpasswords/vault/EffShortWordList.kt+1302 −0app/src/main/java/com/peachpasswords/vault/PasswordGenerator.kt+13 −0app/src/test/java/com/peachpasswords/autofill/PasswordPolicyTest.kt+1 −1app/src/test/java/com/peachpasswords/vault/PasswordGeneratorTest.kt+23 −0app/src/main/java/com/peachpasswords/autofill/PasswordPolicy.kt+1 −1
@@ -35,7 +35,7 @@3535 3636 companion object {3737 const val DEFAULT_LENGTH = 2038- const val HARD_MAX = 12838+ const val HARD_MAX = 2563939 4040 /**4141 * Build a policy from a password field's HTML attributes (keys lower-cased).app/src/main/java/com/peachpasswords/vault/EffShortWordList.kt+1302 −0
@@ -0,0 +1,1302 @@1+package com.peachpasswords.vault2+3+/** EFF short word list, published 2016-09-08. */4+internal object EffShortWordList {5+ val words: List<String> = """acid6+acorn7+acre8+acts9+afar10+affix11+aged12+agent13+agile14+aging15+agony16+ahead17+aide18+aids19+aim20+ajar21+alarm22+alias23+alibi24+alien25+alike26+alive27+aloe28+aloft29+aloha30+alone31+amend32+amino33+ample34+amuse35+angel36+anger37+angle38+ankle39+apple40+april41+apron42+aqua43+area44+arena45+argue46+arise47+armed48+armor49+army50+aroma51+array52+arson53+art54+ashen55+ashes56+atlas57+atom58+attic59+audio60+avert61+avoid62+awake63+award64+awoke65+axis66+bacon67+badge68+bagel69+baggy70+baked71+baker72+balmy73+banjo74+barge75+barn76+bash77+basil78+bask79+batch80+bath81+baton82+bats83+blade84+blank85+blast86+blaze87+bleak88+blend89+bless90+blimp91+blink92+bloat93+blob94+blog95+blot96+blunt97+blurt98+blush99+boast100+boat101+body102+boil103+bok104+bolt105+boned106+boney107+bonus108+bony109+book110+booth111+boots112+boss113+botch114+both115+boxer116+breed117+bribe118+brick119+bride120+brim121+bring122+brink123+brisk124+broad125+broil126+broke127+brook128+broom129+brush130+buck131+bud132+buggy133+bulge134+bulk135+bully136+bunch137+bunny138+bunt139+bush140+bust141+busy142+buzz143+cable144+cache145+cadet146+cage147+cake148+calm149+cameo150+canal151+candy152+cane153+canon154+cape155+card156+cargo157+carol158+carry159+carve160+case161+cash162+cause163+cedar164+chain165+chair166+chant167+chaos168+charm169+chase170+cheek171+cheer172+chef173+chess174+chest175+chew176+chief177+chili178+chill179+chip180+chomp181+chop182+chow183+chuck184+chump185+chunk186+churn187+chute188+cider189+cinch190+city191+civic192+civil193+clad194+claim195+clamp196+clap197+clash198+clasp199+class200+claw201+clay202+clean203+clear204+cleat205+cleft206+clerk207+click208+cling209+clink210+clip211+cloak212+clock213+clone214+cloth215+cloud216+clump217+coach218+coast219+coat220+cod221+coil222+coke223+cola224+cold225+colt226+coma227+come228+comic229+comma230+cone231+cope232+copy233+coral234+cork235+cost236+cot237+couch238+cough239+cover240+cozy241+craft242+cramp243+crane244+crank245+crate246+crave247+crawl248+crazy249+creme250+crepe251+crept252+crib253+cried254+crisp255+crook256+crop257+cross258+crowd259+crown260+crumb261+crush262+crust263+cub264+cult265+cupid266+cure267+curl268+curry269+curse270+curve271+curvy272+cushy273+cut274+cycle275+dab276+dad277+daily278+dairy279+daisy280+dance281+dandy282+darn283+dart284+dash285+data286+date287+dawn288+deaf289+deal290+dean291+debit292+debt293+debug294+decaf295+decal296+decay297+deck298+decor299+decoy300+deed301+delay302+denim303+dense304+dent305+depth306+derby307+desk308+dial309+diary310+dice311+dig312+dill313+dime314+dimly315+diner316+dingy317+disco318+dish319+disk320+ditch321+ditzy322+dizzy323+dock324+dodge325+doing326+doll327+dome328+donor329+donut330+dose331+dot332+dove333+down334+dowry335+doze336+drab337+drama338+drank339+draw340+dress341+dried342+drift343+drill344+drive345+drone346+droop347+drove348+drown349+drum350+dry351+duck352+duct353+dude354+dug355+duke356+duo357+dusk358+dust359+duty360+dwarf361+dwell362+eagle363+early364+earth365+easel366+east367+eaten368+eats369+ebay370+ebony371+ebook372+echo373+edge374+eel375+eject376+elbow377+elder378+elf379+elk380+elm381+elope382+elude383+elves384+email385+emit386+empty387+emu388+enter389+entry390+envoy391+equal392+erase393+error394+erupt395+essay396+etch397+evade398+even399+evict400+evil401+evoke402+exact403+exit404+fable405+faced406+fact407+fade408+fall409+false410+fancy411+fang412+fax413+feast414+feed415+femur416+fence417+fend418+ferry419+fetal420+fetch421+fever422+fiber423+fifth424+fifty425+film426+filth427+final428+finch429+fit430+five431+flag432+flaky433+flame434+flap435+flask436+fled437+flick438+fling439+flint440+flip441+flirt442+float443+flock444+flop445+floss446+flyer447+foam448+foe449+fog450+foil451+folic452+folk453+food454+fool455+found456+fox457+foyer458+frail459+frame460+fray461+fresh462+fried463+frill464+frisk465+from466+front467+frost468+froth469+frown470+froze471+fruit472+gag473+gains474+gala475+game476+gap477+gas478+gave479+gear480+gecko481+geek482+gem483+genre484+gift485+gig486+gills487+given488+giver489+glad490+glass491+glide492+gloss493+glove494+glow495+glue496+goal497+going498+golf499+gong500+good501+gooey502+goofy503+gore504+gown505+grab506+grain507+grant508+grape509+graph510+grasp511+grass512+grave513+gravy514+gray515+green516+greet517+grew518+grid519+grief520+grill521+grip522+grit523+groom524+grope525+growl526+grub527+grunt528+guide529+gulf530+gulp531+gummy532+guru533+gush534+gut535+guy536+habit537+half538+halo539+halt540+happy541+harm542+hash543+hasty544+hatch545+hate546+haven547+hazel548+hazy549+heap550+heat551+heave552+hedge553+hefty554+help555+herbs556+hers557+hub558+hug559+hula560+hull561+human562+humid563+hump564+hung565+hunk566+hunt567+hurry568+hurt569+hush570+hut571+ice572+icing573+icon574+icy575+igloo576+image577+ion578+iron579+islam580+issue581+item582+ivory583+ivy584+jab585+jam586+jaws587+jazz588+jeep589+jelly590+jet591+jiffy592+job593+jog594+jolly595+jolt596+jot597+joy598+judge599+juice600+juicy601+july602+jumbo603+jump604+junky605+juror606+jury607+keep608+keg609+kept610+kick611+kilt612+king613+kite614+kitty615+kiwi616+knee617+knelt618+koala619+kung620+ladle621+lady622+lair623+lake624+lance625+land626+lapel627+large628+lash629+lasso630+last631+latch632+late633+lazy634+left635+legal636+lemon637+lend638+lens639+lent640+level641+lever642+lid643+life644+lift645+lilac646+lily647+limb648+limes649+line650+lint651+lion652+lip653+list654+lived655+liver656+lunar657+lunch658+lung659+lurch660+lure661+lurk662+lying663+lyric664+mace665+maker666+malt667+mama668+mango669+manor670+many671+map672+march673+mardi674+marry675+mash676+match677+mate678+math679+moan680+mocha681+moist682+mold683+mom684+moody685+mop686+morse687+most688+motor689+motto690+mount691+mouse692+mousy693+mouth694+move695+movie696+mower697+mud698+mug699+mulch700+mule701+mull702+mumbo703+mummy704+mural705+muse706+music707+musky708+mute709+nacho710+nag711+nail712+name713+nanny714+nap715+navy716+near717+neat718+neon719+nerd720+nest721+net722+next723+niece724+ninth725+nutty726+oak727+oasis728+oat729+ocean730+oil731+old732+olive733+omen734+onion735+only736+ooze737+opal738+open739+opera740+opt741+otter742+ouch743+ounce744+outer745+oval746+oven747+owl748+ozone749+pace750+pagan751+pager752+palm753+panda754+panic755+pants756+panty757+paper758+park759+party760+pasta761+patch762+path763+patio764+payer765+pecan766+penny767+pep768+perch769+perky770+perm771+pest772+petal773+petri774+petty775+photo776+plank777+plant778+plaza779+plead780+plot781+plow782+pluck783+plug784+plus785+poach786+pod787+poem788+poet789+pogo790+point791+poise792+poker793+polar794+polio795+polka796+polo797+pond798+pony799+poppy800+pork801+poser802+pouch803+pound804+pout805+power806+prank807+press808+print809+prior810+prism811+prize812+probe813+prong814+proof815+props816+prude817+prune818+pry819+pug820+pull821+pulp822+pulse823+puma824+punch825+punk826+pupil827+puppy828+purr829+purse830+push831+putt832+quack833+quake834+query835+quiet836+quill837+quilt838+quit839+quota840+quote841+rabid842+race843+rack844+radar845+radio846+raft847+rage848+raid849+rail850+rake851+rally852+ramp853+ranch854+range855+rank856+rant857+rash858+raven859+reach860+react861+ream862+rebel863+recap864+relax865+relay866+relic867+remix868+repay869+repel870+reply871+rerun872+reset873+rhyme874+rice875+rich876+ride877+rigid878+rigor879+rinse880+riot881+ripen882+rise883+risk884+ritzy885+rival886+river887+roast888+robe889+robin890+rock891+rogue892+roman893+romp894+rope895+rover896+royal897+ruby898+rug899+ruin900+rule901+runny902+rush903+rust904+rut905+sadly906+sage907+said908+saint909+salad910+salon911+salsa912+salt913+same914+sandy915+santa916+satin917+sauna918+saved919+savor920+sax921+say922+scale923+scam924+scan925+scare926+scarf927+scary928+scoff929+scold930+scoop931+scoot932+scope933+score934+scorn935+scout936+scowl937+scrap938+scrub939+scuba940+scuff941+sect942+sedan943+self944+send945+sepia946+serve947+set948+seven949+shack950+shade951+shady952+shaft953+shaky954+sham955+shape956+share957+sharp958+shed959+sheep960+sheet961+shelf962+shell963+shine964+shiny965+ship966+shirt967+shock968+shop969+shore970+shout971+shove972+shown973+showy974+shred975+shrug976+shun977+shush978+shut979+shy980+sift981+silk982+silly983+silo984+sip985+siren986+sixth987+size988+skate989+skew990+skid991+skier992+skies993+skip994+skirt995+skit996+sky997+slab998+slack999+slain1000+slam1001+slang1002+slash1003+slate1004+slaw1005+sled1006+sleek1007+sleep1008+sleet1009+slept1010+slice1011+slick1012+slimy1013+sling1014+slip1015+slit1016+slob1017+slot1018+slug1019+slum1020+slurp1021+slush1022+small1023+smash1024+smell1025+smile1026+smirk1027+smog1028+snack1029+snap1030+snare1031+snarl1032+sneak1033+sneer1034+sniff1035+snore1036+snort1037+snout1038+snowy1039+snub1040+snuff1041+speak1042+speed1043+spend1044+spent1045+spew1046+spied1047+spill1048+spiny1049+spoil1050+spoke1051+spoof1052+spool1053+spoon1054+sport1055+spot1056+spout1057+spray1058+spree1059+spur1060+squad1061+squat1062+squid1063+stack1064+staff1065+stage1066+stain1067+stall1068+stamp1069+stand1070+stank1071+stark1072+start1073+stash1074+state1075+stays1076+steam1077+steep1078+stem1079+step1080+stew1081+stick1082+sting1083+stir1084+stock1085+stole1086+stomp1087+stony1088+stood1089+stool1090+stoop1091+stop1092+storm1093+stout1094+stove1095+straw1096+stray1097+strut1098+stuck1099+stud1100+stuff1101+stump1102+stung1103+stunt1104+suds1105+sugar1106+sulk1107+surf1108+sushi1109+swab1110+swan1111+swarm1112+sway1113+swear1114+sweat1115+sweep1116+swell1117+swept1118+swim1119+swing1120+swipe1121+swirl1122+swoop1123+swore1124+syrup1125+tacky1126+taco1127+tag1128+take1129+tall1130+talon1131+tamer1132+tank1133+taper1134+taps1135+tarot1136+tart1137+task1138+taste1139+tasty1140+taunt1141+thank1142+thaw1143+theft1144+theme1145+thigh1146+thing1147+think1148+thong1149+thorn1150+those1151+throb1152+thud1153+thumb1154+thump1155+thus1156+tiara1157+tidal1158+tidy1159+tiger1160+tile1161+tilt1162+tint1163+tiny1164+trace1165+track1166+trade1167+train1168+trait1169+trap1170+trash1171+tray1172+treat1173+tree1174+trek1175+trend1176+trial1177+tribe1178+trick1179+trio1180+trout1181+truce1182+truck1183+trump1184+trunk1185+try1186+tug1187+tulip1188+tummy1189+turf1190+tusk1191+tutor1192+tutu1193+tux1194+tweak1195+tweet1196+twice1197+twine1198+twins1199+twirl1200+twist1201+uncle1202+uncut1203+undo1204+unify1205+union1206+unit1207+untie1208+upon1209+upper1210+urban1211+used1212+user1213+usher1214+utter1215+value1216+vapor1217+vegan1218+venue1219+verse1220+vest1221+veto1222+vice1223+video1224+view1225+viral1226+virus1227+visa1228+visor1229+vixen1230+vocal1231+voice1232+void1233+volt1234+voter1235+vowel1236+wad1237+wafer1238+wager1239+wages1240+wagon1241+wake1242+walk1243+wand1244+wasp1245+watch1246+water1247+wavy1248+wheat1249+whiff1250+whole1251+whoop1252+wick1253+widen1254+widow1255+width1256+wife1257+wifi1258+wilt1259+wimp1260+wind1261+wing1262+wink1263+wipe1264+wired1265+wiry1266+wise1267+wish1268+wispy1269+wok1270+wolf1271+womb1272+wool1273+woozy1274+word1275+work1276+worry1277+wound1278+woven1279+wrath1280+wreck1281+wrist1282+xerox1283+yahoo1284+yam1285+yard1286+year1287+yeast1288+yelp1289+yield1290+yo-yo1291+yodel1292+yoga1293+yoyo1294+yummy1295+zebra1296+zero1297+zesty1298+zippy1299+zone1300+zoom1301+""".lineSequence().filter { it.isNotEmpty() }.toList()1302+}app/src/main/java/com/peachpasswords/vault/PasswordGenerator.kt+13 −0
@@ -9,6 +9,10 @@99 * modulo-bias rejection over crypto.getRandomValues.1010 */1111 object PasswordGenerator {12+ const val MIN_PASSPHRASE_WORDS = 413+ const val DEFAULT_PASSPHRASE_WORDS = 514+ const val MAX_PASSPHRASE_WORDS = 1215+1216 private const val LOWER = "abcdefghijklmnopqrstuvwxyz"1317 private const val UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"1418 private const val NUMBERS = "0123456789"@@ -41,5 +45,14 @@4145 return buildString(length) {4246 repeat(length) { append(chars[rng.nextInt(chars.length)]) }4347 }48+ }49+50+ fun generatePassphrase(51+ wordCount: Int = DEFAULT_PASSPHRASE_WORDS,52+ separator: String = "-",53+ ): String {54+ val count = wordCount.coerceIn(MIN_PASSPHRASE_WORDS, MAX_PASSPHRASE_WORDS)55+ return List(count) { EffShortWordList.words[rng.nextInt(EffShortWordList.words.size)] }56+ .joinToString(separator)4457 }4558 }app/src/test/java/com/peachpasswords/autofill/PasswordPolicyTest.kt+1 −1
@@ -56,7 +56,7 @@5656 }5757 5858 @Test fun generation_caps_at_hard_max() {59- assertEquals(128, PasswordPolicy(maxLength = 500).generationLength())59+ assertEquals(256, PasswordPolicy(maxLength = 500).generationLength())6060 }6161 6262 @Test fun generation_snaps_up_to_min() {app/src/test/java/com/peachpasswords/vault/PasswordGeneratorTest.kt+23 −0
@@ -4,6 +4,7 @@44 import org.junit.Assert.assertFalse55 import org.junit.Assert.assertTrue66 import org.junit.Test7+import java.security.MessageDigest78 89 class PasswordGeneratorTest {910 @Test fun respects_length() {@@ -32,5 +33,27 @@3233 )3334 assertEquals(30, pw.length)3435 assertTrue(pw.all { it in 'a'..'z' })36+ }37+38+ @Test fun passphrase_defaults_to_five_words() {39+ assertEquals(5, PasswordGenerator.generatePassphrase().split("-").size)40+ }41+42+ @Test fun passphrase_supports_four_through_twelve_words() {43+ assertEquals(4, PasswordGenerator.generatePassphrase(wordCount = 4).split("-").size)44+ assertEquals(12, PasswordGenerator.generatePassphrase(wordCount = 12).split("-").size)45+ }46+47+ @Test fun passphrase_uses_the_selected_separator() {48+ assertEquals(8, PasswordGenerator.generatePassphrase(wordCount = 8, separator = ".").split(".").size)49+ }50+51+ @Test fun eff_short_word_list_matches_the_published_source() {52+ val normalized = EffShortWordList.words.joinToString(separator = "\n", postfix = "\n")53+ val digest = MessageDigest.getInstance("SHA-256")54+ .digest(normalized.toByteArray())55+ .joinToString("") { "%02x".format(it) }56+ assertEquals(1296, EffShortWordList.words.size)57+ assertEquals("36ecca49e4fa20ca84b176c32f2e9c82f98f446585190e75f9879a95c08247bf", digest)3558 }3659 }