From eb552a916457014dfff4fbd0ed920ba0c02f6ff1 Mon Sep 17 00:00:00 2001 From: Joachim Hummel Date: Thu, 13 Nov 2025 13:41:29 +0000 Subject: [PATCH] first commit --- __pycache__/algorithms.cpython-312.pyc | Bin 0 -> 2047 bytes __pycache__/argon2_algorithm.cpython-312.pyc | Bin 0 -> 2515 bytes __pycache__/bcrypt_algorithm.cpython-312.pyc | Bin 0 -> 2123 bytes __pycache__/pbkdf2_algorithm.cpython-312.pyc | Bin 0 -> 2666 bytes __pycache__/salt.cpython-312.pyc | Bin 5031 -> 5042 bytes salt.py | 41 +++++++++++++++--- ...st_algorithms.cpython-312-pytest-9.0.1.pyc | Bin 0 -> 11855 bytes .../test_cli.cpython-312-pytest-9.0.1.pyc | Bin 2904 -> 7646 bytes .../test_hashing.cpython-312-pytest-9.0.1.pyc | Bin 5290 -> 6549 bytes tests/test_cli.py | 30 +++++++++++++ 10 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 __pycache__/algorithms.cpython-312.pyc create mode 100644 __pycache__/argon2_algorithm.cpython-312.pyc create mode 100644 __pycache__/bcrypt_algorithm.cpython-312.pyc create mode 100644 __pycache__/pbkdf2_algorithm.cpython-312.pyc create mode 100644 tests/__pycache__/test_algorithms.cpython-312-pytest-9.0.1.pyc diff --git a/__pycache__/algorithms.cpython-312.pyc b/__pycache__/algorithms.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..676f26fdb1d5895c7518d05e3a6371141305075f GIT binary patch literal 2047 zcmZuy%TF6e7@t|M?ZxW{fjkRIrvwOYs2x=;hZa@gP?5e!1x*gF&}!`&n}zi*on1h- zazHJ;Qz;UMs`pgm{8MjVu$c9}pfF`f*GhB&E1R zN(r72NuFGUDW2xWfnG9rhL1o$!m~UDeG2TDu30iwpDv|UpDAS;Wl==fd$L*r}d zhknI(D;JB z&bX*L9>8GXh8TkVe@L0#;};a77!Zn54i{eNR2?BJ+AvJeO^k=GP&Q~@Yd&}ce3?Dq z-|?dox|!@av+u z>D!eJr(Uc%VG)fLhp=upA|0LG%=R5nz;Omlv@vz|$xFj*gF-3@c(`3=QG6<-Q*B(} zQL`N{2w4#NQgDX1tEl4@g%ycen~zH{L}VI7Wc0{J25v#J5}^bL1t>8lv$!v@tFCH} z4p4VyuE44sMSco;%3RBmIW&3=1#(v)6(gCz zAqoS&0Pp^h{HcHba&-KM$8BAUr_T)#oddY7d6herutTEng!Ra@mcCqmy!zQUkG@)~ zP}tXNm=o~P_Pd}Qk!K|At$@CHIYD6!OGPE;d#kEMg@nir(j4kRl|{|<%eLDu^G8Iwo6yNV=gL>r}ju7Oto#K{8l=3%&p&2N`$w-oY1#`cdwu-0wP5oG);} zL{wZJf^w0|E|u93xvIwLGx9U}MLX_#;(I#G`WEb2BT#<#mj$Nf5V>-LVJKNu`gKLK z_e>R<<4?RT&)*x`{SoVOj#5u;cSn3Gr7w{>ni!^@sfloi^)%f7HhjSx2w~`0F0_n=GxPdkcw$br^vRAl;6T6iy@3%sB4I!3VLz&y-Jd}J z3@FFlLC-hf3EF(Hs!D{p@Fp|A+6}9~+U-Y+4IZ|j0IyIY@MS2tih87PiAHcKx1$`I z8xRj95}t)Gz{=Vu|Cm>v-~VH5>SS!{bZq+6oN4JZiYL}DdZ<$!oibeUJpt2qaaz?W zPOA+N1=O1(cpX;8dOj;BUfd+&Q9Wxp_oR2Fr(4! z@)obYKY$;N!XxW@7iP*8+1MVUc*z5AjK$7N@rf*gO^i^m1mbm!QW}xPS7hoHnK)0F wG<|5C6X;&wAv5>(%~s}}Q!?95XmqZf(&_DXR-?1+G@&>DA~(*+4dtc(03s~-rT_o{ literal 0 HcmV?d00001 diff --git a/__pycache__/argon2_algorithm.cpython-312.pyc b/__pycache__/argon2_algorithm.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..526b964d3bcfd02b577629119f7d976216c4f9a7 GIT binary patch literal 2515 zcmZuzU2GIp6uvXNGdsK8{?IO4x+XG03v89G5(Gkw(trqvjZ#HfqLb;)-Q8K|r{0;R z-Ay6H^Z_4?Au;JI@d;C3OibjJ#0L^zXj)SkNhCo`d@EF=X=36zcXqb8a+{ue?$3Pp zoO8c(?*7=_og&b(!B(>_6Y>BDQHzI)u-*h^ff%Gn48agB!4`|6fO^b|6=S@Q7vs>! zEy+D6Lbv9|l z^2w$;&ML06Pt~o8%S^v&tEN3|QJXrx?whVt_#L6W2t6)ZKK%BHV{ zK-RhYrB+bdM#Tsb)^~8D{PtQD!a1U~=Ndv@Y>u9EOy2}In^c{FAgTr}>vhYIf;+7< z-KIWeUST3HGQ9mDp`ketI3b98)GB)jscwvpRb88o)m*()HSMvA>5qB3<&TASYVB(( zOg92W(@Z#6)0*2lye~v6TL9EcgSbq79UNI6+IC>ny3pmXKv^Jj zq=vH{tp-8qY;!`yr;ET=Uy9aih}hBQVzp$)6bub9LWuerSkl=xca_CSl8-h2LE5SM z=H=EsyxQo}3#pXaY7?$c4@Wmqp$=ubPd(N2J=L9YRE(}_I&e9TZdnagcMO$Lzs?-5 z4WX+g7qh~roI|STGd#?%>iB8Nsv7|4S7``_2v6L28|8i40#>O#?KdKnvdj2)+SGyl z{B#5=*DWhNOZRw>tA#dHKsKbhU*3BtFEfl*5Jxfv@|5n;1N(y{Y^F}hHE1A5y+LuD zk27RLphQU#$RE!Dx4fVW5wy@V4;hN#W8I*z0T9hhC&h68R#@?lfw)Z8ddT223)WR@ zHM@H$yZgGboPFs^*Zsc!FORQghLXniK=aml0%-_4iO)+r;`$g)-u#|OtMx_NX7Be$x}S-(vNTLsOd#h-BR)fB zW9P_>ke8aXVI6&v+erRY&%4cER%yyD8v`EDd zJ^}%>%u30jdpUJAH@cJ?y?*G1v64Hwnme_WJ9X>ea&Gdt(%Ze|$3#dD-5uDr7K47n!w`KsE{;p& zrnG1L#n{a;0ptWE8FwfK*%ZiOF=_Vtb*LccVd@3U{15XA-^4}$gY87Ywc)n53$!3U z<+@g0!BX$Q6QXHBO4DrDs9UI~HSLqSZnahtnr65q++rH=e4AyHGKQq&3Cu8HUlX2W zVFVRiLV;J{9RV>0=+|U2kX=ilrl6KY zElpBAe{_Quf+Hj_sh`n`=>d^8AFX^hdma|ihjJZCEcn3iQQ;h8+fl<8B77jXKv{xc zCIvcMqSN?O#M>kqH#*MyB?Aq r4@mdVr1v3t?iX_OFL_uPdPG3{IUx{X^pQ-2fvc}A4-EfAMmXxfTM}Zx literal 0 HcmV?d00001 diff --git a/__pycache__/bcrypt_algorithm.cpython-312.pyc b/__pycache__/bcrypt_algorithm.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e51414d380fb4735f398a4802d6b29e263f13bc GIT binary patch literal 2123 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 LcKt~@otysyh(%Es literal 0 HcmV?d00001 diff --git a/__pycache__/salt.cpython-312.pyc b/__pycache__/salt.cpython-312.pyc index bde62808d85955613cda831eda00d9c807d5c84b..8132b80da24f29d650cb253525619c2d5bb82508 100644 GIT binary patch literal 5042 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 MfZ7Y{rgB>R52BQ^)&Kwi literal 5031 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 argparse.ArgumentParser: + from algorithms import list_algorithms + + available_algos = ", ".join(list_algorithms()) parser = argparse.ArgumentParser( - description="Erstellt sichere Password-Hashes (PBKDF2, Argon2, bcrypt) oder verifiziert bestehende Werte." + description=f"Erstellt sichere Password-Hashes oder verifiziert bestehende Werte. " + f"Verfügbare Algorithmen (--algorithm): {available_algos}" ) subparsers = parser.add_subparsers(dest="command") hash_parser = subparsers.add_parser( - "hash", help="Erstellt ein Salt und einen Hash für ein Passwort." + "hash", help=f"Erstellt ein Salt und einen Hash (--algorithm: {available_algos})." ) hash_parser.add_argument("password", help="Klartext-Passwort zum Hashen.") - verify_parser = subparsers.add_parser("verify", help="Überprüft ein Passwort.") + hash_parser.add_argument( + "--algorithm", + "-a", + choices=list_algorithms(), + default="pbkdf2", + help="Hash-Algorithmus (Standard: pbkdf2)", + ) + verify_parser = subparsers.add_parser( + "verify", help=f"Überprüft ein Passwort (--algorithm: {available_algos})." + ) verify_parser.add_argument("password", help="Klartext-Passwort zur Überprüfung.") verify_parser.add_argument("salt", help="Base64-kodiertes Salt.") verify_parser.add_argument("hash", help="Base64-kodierter Hash.") + verify_parser.add_argument( + "--algorithm", + "-a", + choices=list_algorithms(), + default="pbkdf2", + help="Hash-Algorithmus (Standard: pbkdf2)", + ) return parser @@ -65,8 +85,17 @@ def _normalize_args(argv: Sequence[str] | None) -> list[str]: """Erlaube ``python3 salt.py `` als Abkürzung für ``hash``.""" if not argv: return [] - if argv[0] in {"hash", "verify"} or argv[0].startswith("-"): + # If it starts with a subcommand, leave as-is + if argv[0] in {"hash", "verify"}: return list(argv) + # If it starts with help flags, leave as-is + if argv[0] in {"-h", "--help"}: + return list(argv) + # If it starts with --algorithm or -a, prepend "hash" + # This allows: python3 salt.py --algorithm argon2 mypassword + if argv[0] in {"--algorithm", "-a"}: + return ["hash", *argv] + # Otherwise (plain password), prepend "hash" return ["hash", *argv] @@ -76,7 +105,7 @@ def main(argv: Sequence[str] | None = None) -> int: args = parser.parse_args(_normalize_args(arg_list)) if args.command == "verify": - if verify_password(args.password, args.salt, args.hash): + if verify_password(args.password, args.salt, args.hash, algorithm=args.algorithm): print("✓ Passwort korrekt") return 0 print("✗ Passwort falsch") @@ -85,7 +114,7 @@ def main(argv: Sequence[str] | None = None) -> int: if args.command != "hash": parser.error('Bitte einen Hash generieren oder "verify" verwenden.') - salt, hash_value = hash_password(args.password) + salt, hash_value = hash_password(args.password, algorithm=args.algorithm) print(f"Salt: {salt}") print(f"Hash: {hash_value}") return 0 diff --git a/tests/__pycache__/test_algorithms.cpython-312-pytest-9.0.1.pyc b/tests/__pycache__/test_algorithms.cpython-312-pytest-9.0.1.pyc new file mode 100644 index 0000000000000000000000000000000000000000..78dadd3d9d9899cdc8550f19699ab97ea560a34b GIT binary patch literal 11855 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 delta 256 zcmca-eM5}zG%qg~0}$k%7R~f!oX97^Xg5*aK$ta!xrHT)GleyU1xRyMGHSAIoYcz1 zs5x1JxfMvxV_w0iu-TpE2n(MkR}nMNfFc$UAvjrtQ%zix;}%PCVou2|wv5E$jMS7O zNsye>WCaOv{$dUwTLB7+sWdaE zBr~tLNO-citg)RS$Q(5gfv{2m#MJ;2D;bJFCKSm7iC-Kxx%nxjIjMF<`amut5EqM2 QUMMTd^@W3((E_Xx0Q{~v=Kufz diff --git a/tests/__pycache__/test_hashing.cpython-312-pytest-9.0.1.pyc b/tests/__pycache__/test_hashing.cpython-312-pytest-9.0.1.pyc index 0b005623bbe4931dc69cac0175982f53f5802366..3c68c5b0a56b4d2f89170d204996d53bcad3b862 100644 GIT binary patch delta 1035 zcmY*YO-vI}5Z<@D-R|~hOKGVPC@v;gmLCb0G{qobQWH%K{zN?xlV<5|rJ<$G+ikF< zO)+xtpo!#Z~=dCSPRv*)KhL%Zb!FQL(v|)&aLn>4&AQvAe|s>AYHn!!pyh}NEP2L9oW$3R$k~v zsB7!Fy;mSR?qEA^gIKD71rXRyL7@;Jf88qTB<*qtg|?>TeuRQs^PW2_I!!)#H*R== zRQ1LaS~?xaMh+*knVg0V?4iyr6j~|xDEKMV(}*|#deu3VE5tR^G_V!Mr|4-1`Pg~| z(y_h~6egp-4=70HJsr2+vkdc+u@G?TOGi5UhIy^?iImppH+#==}$@zAT7LHi7!a1V`=2Bfm6wXGN+ky@f?)5n8muHB@#x? zG8HX-KZ{e=Tto+@HoW9 z-o9KRqME9sglT!l!-GMJ)F4ry*91E$xG3}kOk)}F#JK514u=3*V>Zbw&S=({NiT&` zU%1>!PY37+$4^ukUxcdS%@2pl56i=2;6bNr?f@(^zkJGi;B9ozH~#S2a_sTh@0~pr zKDHeNcrv*bSs&d9Y)AK;G1%`qW8e7W=PNMElMTxk%5JE8d~7Z9KM!Gd{y0rokB&<}=LVIE1pncX4qZm|F#iC#y%C`R delta 320 zcmbPgyh@YrG%qg~0}$986V05(G?7n&(Ql%B^{fsnWb$bce#5FrR6gg}Hah!6o1njA%BI0g06iMIhZpQb6JthfQvNN@-52U6Cb_ X%Lv59@{=i None: salt, hashed = hash_password("secret-value") assert main(["verify", "secret-value", salt, hashed]) == 0 assert main(["verify", "wrong", salt, hashed]) == 1 + + +def test_main_hash_with_algorithm_pbkdf2() -> None: + """Test hash command with --algorithm pbkdf2.""" + assert main(["hash", "--algorithm", "pbkdf2", "test-password"]) == 0 + + +def test_main_hash_with_algorithm_argon2() -> None: + """Test hash command with --algorithm argon2.""" + assert main(["hash", "--algorithm", "argon2", "test-password"]) == 0 + + +def test_main_hash_with_algorithm_bcrypt() -> None: + """Test hash command with --algorithm bcrypt.""" + assert main(["hash", "--algorithm", "bcrypt", "test-password"]) == 0 + + +def test_main_verify_with_algorithm() -> None: + """Test verify command with --algorithm option.""" + # Test with each algorithm + for algo in ["pbkdf2", "argon2", "bcrypt"]: + salt, hashed = hash_password("test-pw", algorithm=algo) + assert main(["verify", "--algorithm", algo, "test-pw", salt, hashed]) == 0 + assert main(["verify", "--algorithm", algo, "wrong", salt, hashed]) == 1 + + +def test_main_hash_algorithm_shortcut() -> None: + """Test shortcut syntax with --algorithm option.""" + # Should support: python3 salt.py --algorithm argon2 mypassword + assert main(["--algorithm", "argon2", "test-password"]) == 0