Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ log.txt
secureData*.txt
logfile.txt
rmc_log.txt
*secureData*.txt
logfileConf.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public User getUser(String email) throws AuthDatabaseException, ModelException {
public boolean addUser(User user) throws AuthDatabaseException {
//Logger.info("AuthDatabaseManager, addUser. User: " + user.email);
//String hash = Crypto.hash(user.getPassword());
String password = Crypto.hashPassword(user.getPassword(), false);
String password = Crypto.hashPassword(user.getPassword());
user.setPassword(password);
try {
return create(user);
Expand All @@ -81,7 +81,7 @@ public boolean isUserPresent(String email) throws AuthDatabaseException, ModelEx

@Override
public boolean editPassword(String email, String pass) throws AuthDatabaseException, ModelException {
String password = Crypto.hashPassword(pass, false);
String password = Crypto.hashPassword(pass);
try {
return update(new User(email, password, null));
} catch (DatabaseException e) {
Expand All @@ -102,7 +102,22 @@ public boolean editAdmin(String email, Boolean isAdmin) throws AuthDatabaseExcep
public boolean checkPassword(String email, String pass) throws AuthDatabaseException, ModelException {
User user = getUser(email);
if (user != null) {
return Crypto.verifyPassword(user.getPassword(), pass);
boolean passwordMatches = Crypto.verifyPassword(user.getPassword(), pass);
if (passwordMatches) {
// Check if the hash needs to be upgraded
String decodedDbHash = new String(java.util.Base64.getUrlDecoder().decode(user.getPassword()));
if (decodedDbHash.startsWith("000000000")) {
// Old hash format, upgrade it
try {
editPassword(email, pass);
Logger.info("Password for user " + email + " has been migrated to the new hash format.");
} catch (AuthDatabaseException | ModelException e) {
Logger.error("Failed to migrate password for user " + email, e);
// Don't fail the login, but log the error. The user can still log in.
}
}
}
return passwordMatches;
} else {
return false;
}
Expand Down
1 change: 1 addition & 0 deletions JFramework/crypto/clientSecureData.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
oQMPy0fTLRdPWzyQN_a8Z3ZSx86PNn0Kmx7YaPDJWWmrCMtYyRqpKexxWLuhC_7-3Sh7bv4ntIZ2QyHfTPsfZwEXjcgsDuplwLT3sshGCzesJGseey0uVT6UHxrTWq-4eiebbeH9OcuD9BbHLSde4Wtvphgnj7nnTlFNWpq2fsd8a1qnCMU0-irML-6_vwuH57CO9oSCuqqwoKYPXPY1H5MMBdeUqnltGXpZWLpuqUkyTgULjkwJMxxsFFrcVt0dO2Ms4mAZOT0Ih0FBe06eRQAVTIZDIudwLoHVqdSdh4pBzjs6OS77GduFc9AfY0Yy_cv28bYbCmTD5OTL8GhB6An_03_alHPI165-PQ3RiNZazGiS88xgtNyI5NB5GVyBY3HLhaWxi2Phvk6uTnBpJUewJ1v8aJ3Rtz36H-GqonMXS4EkkVlnn8gQdp8sXHz40Crm-NC_Ilsee6Z8X6h8it_ODyp0rgjE8zRx9oOUlUdsraYG7jwqXPDY7Jvm8-o4jaarkkj78-vIql6Xzc_CMu0a8YSpOVG1IvRAk1h0sH9eoS8iZRlKvIJB_RTOjq1L-teK50htuBTF53oQreSPUG77LIoZqSvpBbdtqFeSOyDlZdRjLF0nzKlNrMFgUCcE-ynfGgHBaP6xuK_6zGreouB96__AiiL66yEYp3QX2AILlTWnTRalP08QOP3JPBLUodIqM93ugkfxwROQrSTFiTQxKvl--KrHVbTYkpKFslvsq80dJ9Hs2mbDu41FZbiD9wgXbOTkRxWg8Nrlsbx5cRMGk70YImwZql6KdDiXPyDek0YOycZRkAt2GvqRYotYCh9WvMparnQ1dHHCgAO5FTNJSQeSRaKdLhsJEfKvXNSiKFCDLsnaEa3pWXt7-IXNve3oyJIMcwH7JsnuMDTY-fQjV4EwvRbuxP0soZe2NcOcxMGaIYkorTNZqB9GyebYobgAMZ0rdJsFrVcrjukxpV_oyRyNwbvRVZGby0Au_NGazUNz41qJXlywynyBwCQtA_k7FNe4Gq2pzoFzSog7mh9Gz_9VlBrSqxSj3X6NfRI4J8C9FWq6_FmrznUiWg1miWTsWXdoWn0iZEq1mBQQ0rPvSkuPtG_1RaUW2p3neywD3zGtFL4YgOdzejCtbkN5pcubvL-6bd5d6l7yyXcQu6gQ0m7yhNn4vXE-xMDjkRK_Dr6ljZ4UXBt3MQfBuPaHi0ONAuzAx2bqfTWGJ2sjH1ez3jUu1AS1JaADHveBNMJxtwkvm4wc6ZfI1aL75U6hSPkNTG8yyG8AJIAuROIIBkQPNJUyZSxDXI0QHJNj6cMNWD2F5DtJaCsEzVfmVjsjfslAmUDsVBDXcLwY4wV7b_hCTho2GAPgcRN2Rj6G0XM7eRtRqOteJu_NqxWjLVUoPk2Arq7anF68Eh4z6Bw19eiPXAY-0bblCVcEROaxCUfjemeWILJEfPlXLSvNsox5fRfam1fWihEEyqv2s6A3Wpm7G69Ou2t8ZC_mgv938EJ2Yv8MORSiERxnbrslz7UuBmut9ckLqbZV9jdQlxOmKg2EOPRTTlbHB0a3mh4fRzLPFRsaco_7xkwwg_eqwltTQlyFLtSckuXS1HzpZQdWr1sulZa4zU3qU_TkTkUMfp1g2G2XaudX_AhppgLqn8tCdd0iyG5ItqsVT5BR1RuOrAntPEeSCAVCHDte4YPim3dnSk43Ga6Ox9et1peOndugZHueowj4p3vWWufrgAVQBCmvLWD-hE465x9kzwLDr6RMDKWVFGFAJTeQpYVff82VeY36lto2G06Rj2ItTzVYf5wa0VCe1aR0-xUndgKXOVRS3ZJJmxWNQnONIiT03qRP9x8BIjBxokiUaaSEjGmWP8Us3dT8I7HbHfe4y9j8b85rhxb1e2YW7IO2RdIQJ79Qz5A6rF64fT0LgUkOf8fsqghNHBxkYFDFT2TXcBE_koyxNqVCg7p2IT8Kg140RDIvodZHYPfT2RDIH7Sw5qLoT-r8icUJReHVJjgisSeuITEOhRenYTj_y0qstnFRviKiOnWZaHe2dsVHcmtn9mCn3DL8NnVb53x01ch_6QFL4EjqQUvALXDFNuZ0nF6-isjwcGLI80x5uREQwVNKMbwcs5_D92xeroI2ZpP7VXeYlRuGGC3M4IevFEALE7Ql0DSF_AvCakajXddoWtXJSmPS6souGvvxfLNitb2L_dIsNmcEpbbwvZbTu7wmvhLHlwZMiEu-5bNA9_Em4aSFIEkMz2O727q7UghW9QTEEKKEIRray2Ol8Hs6trCjEMivcIzi-oZ_uA019b0QzbW4t5UudqgzDlEw008X9u1aT5Dly4zmRq836u06xgjTOe2XtBDBkJGBCwUMfH0GydfceTVMN-WHgrEn3SMsDWnmjtkyCMye41xzCFcb_AOvdUhsuSr-plDS8UHWZrxStwLGMR-JxGbbeVPU9ns8xbXnjXzUoJWXLEUOANkztXXv87gzAknqd7aq5OlfXxr7_nHImOtx3c6gEAxW1KG5VlOSZTcs-8g4gp3Y4VrW9GfU8ZU_nUam0luRhyDlilkWr0FrpnM6J0bExYVgXkCTQki2AqJuGkAbp97AlJU5oSX85kNkxX9cXAsOOfO_xj3HbuweyCQ6XLHCIi7dpW6q0xmf9uSCosbtqaA0SIqDxECs9rWLidik5iCe7h0Lqe3OxuLEUdneVkJRdoMLfagdyOSDpDZ0ZVHH3vxaQl6O4qgkvTRN6-PBmxSGNnMLrvzgj3UAntNKQVmK64UUxJtjkuSrItW-hmdjuUI32Yx8bXzA0YMMOc8O7imD1zwubhtwQ4TdTOSlYEH37Jc3yafXKOsjkjBCNmFrQt1Q_eXQXo8leRgCpyWwRGcS9JGnjSHWavDX1vHekAqIf04hkyNDcqdhZ4k6FS3wwI5oR7Nh4CmuOVou7sC849yGsn7pqtcPdoGm4uQN7JFDIpmJa8e6lIxizsSM9QmK7dZwwvrmz3b-3KGtdsGjD-CIw_UQfxevHcOt6VgI4A3n3O8yE8JStsULqbiO1VwYzRU4NeNFCXjLi99NNwtaCP7r2c_Bg1_I3Hsb9H7pnUHsxkyHQ5BmmeD_GxFyhKqopBLaZtAhOm1HkhaRfr_3koq2c8-iRcVhacd_-V2k9Gdrta30ChXA7SALh7GhGJYc9Mo4_3AT4fCUR-0Of3kiYgvOoQx6QGp8enYTZSvZhbnMEKFV4TV_tGw7rueHEeC0gVPQkgSGudwX2MgqP6NqvmJmgnjKfKDy5ZjF5L6xWkG69JfsH0JJvOoNrpdZjKFijII5JRXTdFqZ2KeOqgZ1O_9Vs9avNYXGDjlRHL-TKBfUEd4pgQ85-PDt_J3a2tVaW5FvQTRdqF9SLhKCuywkyyGoC1cgZtsElcDpgCuI1yhl4LBGtBa_wKhjZ50-tZ3Y0NUy1fR_Cn1M8TA_wOW6_ropPcSKSua2mybJ5EAhWfRgpvioHmEmXorLbSufse_qiIYrqJYY21PsZx7e-AeCzwXDYOjR6EqU2CsSSF3L6pU6n23pV4JKorGjdicBqTQO_RtN73uss0B3GCru2VjsTlicoerUixN50hZ7UiibmOo8KTKaevv_NKp83ROP-FDDhWaq_6xzuh6yhKzpSb0GLfV4MXNcrtD0AIPGm4c_ukHWuTqlSHAc5gCVZtuO19A3xLO2NSuKpz2p2vXBGH_t0rZw2kH5OwdYU3DpbRSDa1FiXv1WetC5xCgKOhUAterKasEUU2Mgb0zdXM42Xr3WbG8VI1HraTMo1wAXp71QI_4P6-0TNIs_s6ubrUpHFo-I5uxUSI9Yn8P2PkdleIM2qs3CujXLD8KdqUk2-icfqShWlRU_GEpqQl_461g_c2t_67W4qf9k6Tlk8XKoKynxitLV2a6VnkS5OOIxgdLOEbazBj0Vvmvhl5GmrsOL9-gLHVdjiURacGg7LWFfMI9i_k63EVWGT23-aXwNRxL5Kkk8Y4ow4zFlVoGaiMO4KnaV6zTzDbuBGmCjic34gX13PTLdqXcZDC04tbAj1bCJZkDa4REjLMS_Ay9Ue1DlBABfEGV5E9yvzoyQhKds1gTIhw8gQwYvBy0llgMK-XuPL75-hHN6bt-prAQ9Xb5_ctnwOdXQWF1dKXUF1aFU3-3wJNimKkf8o5K84tY3hmmecDkA6YxlnPgajTXFZQglmLni4ziY9ba6lJNjzYQUrrmkGDrx_DlCd8D-t71doxD7sQGR8H589kltHa1rqRxFPwetKbvJb6JLQlHi1P2sK_xG
1 change: 1 addition & 0 deletions JFramework/crypto/serverSecureData.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1ZpgrHRLDlhqud-BKq4M4LkofsqlBvBSVfx4EKfn8wwuZowoa7liIEQWzrDzEM-jd9gE3VxRVm3brcaBEal4Oftfb8QohhvAw2PMu48ZV1r1tbNEqc5FwoemtUJgUNYJMbHbMKAUxp5LpZOUhdUT2LP25x9SDP8FK4AwFZHEsUMg5-7LOGk6JYb4Zb29YZUIXpBR5K-9deN-mvyYz5dSUyi55COUZykAKlfQdzYjsGxjLALl-9Oi6Ds5oDT8DXmmxmQ2WKvcxlD8kwb1uhAc59jkuFmcq7ua-z-d2rJrSYFMZ4sRWp4In8ksbauGZZ-UPk1HAegOLPJLR6oXxijyd3I7FnqIx8LNQ-cEIjFvJ9YGwIfLat9oAhYdmdFD7sebwuAID-wqOGA7bRZd0zX9UijriQrzaYzUx25x50mA2Y7iLjnQK4opzQctbrHzZ6nnNdcP3ioQ0N2S-aWaeN7sr5edafJ_njpioTRqKWRBT-AmjlGVXKxJQBuGAHksWNkZx3UE3oZIFV7D2rFV7ng0dpktmX2VLiAl01fcCQDRR5TswPIyuYRkIQ8EdjAfuLkxupIu9IHedkw-E-QhpVfmAyiJrWMFP3JkuoQoLhjkhUzVE187Hvb8BbgVOaZMyS1VuUdfIVlevS9fRmfsDwv0fUyCMrW84OFX-IvHwphYGgp3727Ym2hvFjlfPRGVccs4IkmtKPDouqR6_Q83YhBvbF2y3CE4I0sokEooDZS-IcoIpFN1cXM026ab49OiSiEX0Hv_v5C8XY8ltD1CBpHzYSAgs_DUFfsuaqW3BJFUxkqA3Udx_WRpcbDFur0SgElPXARf6tGh2vFSXVi-HDs45hKmzQ-ySgzENT62RI87nYAFkNMY7CPqwegaRvWLYUfUdzEAWx0McHf8jF63LKmy9LTh6NrPWzjjqgMuCACKfdF85afSFRb5l59aQgNRSJbqSX0DSjhKbKF5wrX-e_XMP1LvjTUmb2doLmKGPzXRPTkQZo_JA4HA0yj4U76u9BkZrNMoBvIR8-y8Kp4ctD6z_nHqg5m0PZbnhc9uMsBU6iLBPVbofegwE-6xS12ev97QFZ2gZCFvyTATfV4XPCFG67jDx0_m7cEWDK8mHMnRs2dpcKjWKgjLJ10cSNAlixc6YE3kgWcecEbfZPqujfYd-8aOjz3kSXNIOoj-bXgT1C2s2CSrB7qwIo0rHG_i7OFAATOw8dSdnZ6mYDOJQW76m3wy0yo785VtRbyjsc6NF1as4zveWZwKWriMv2DmudpjZOlQiR_ZkrfSORNdLLZqCL0yXOPcgVVkdXMmmBNri7Y8lG6aFnIkh1UcwLYXud9lFAU6Vb5SZEjY0Lgumx4I2O3TAyCRA6TdEZ8autHxwF2aomjhnO8dFiLFSK4Haws_L26Dxa837uxFE4nzgkUf7fOOJ6KP2GDbi4aoplYVXMW-KfysMimVNSF6oRVBUq-C-nLIQhnXFnSkDE3TNgyxUzWdNiIIxqzgf8uGV8-6X5IzhKm3jbvZxztVsTJaCS-aHDZLZ2GX9H3dWYvpjhDrmk-3l9x78UdNf1U5CnjYUmMyhBbZSeLYWYy2tgYkp8TATXnK5f3H_FTIVEN9sZCb6_rbZKVtCOvXuvMaUXS01nHnFeVlotKgf6zNI2gd09iVwAC1f5Ct8El4Xdsx_b9MCHF3U8fO-FCatWugz3QJRyAiCv7ytXD3hjbJwN1-GhVOQuumQ7mFT044MFa4vgn04BHu3KYMHUQVxGQZakZ6sQffTYMVhbULt5nTcxTKb65VS7sC9-6c_p_mTfYJFimmc5EIFEQZt6Z6HRO4BZPCkaKO95N_fA3QrAEKub6Foi4vSSNcEAFkzd4O066BJ0PjoQo353rCRYnNNZhnR0pqi0ag0Bj-2IKAslbC9GE8en65i7pq2vkbbbDFfeu2csFlrUQEEI_Mtml3fDnQireq1bR5_q3wc-0CToMmpgfrTOhEbvzxeT1ZFU1xsWEKbI9-s4y-u4HNzjPFedF5y5vNwjHMvDaWwHLGlxM2JVam_3ds_vY3iUUXtnNM4t7QfK5qsUH8UW0YNIknIWDoE3EfYCV_STvotP3L3KTjO5_LZGBtzl4It6IX9BnwRcTZk7MaZMWxqPrChe-Wx9SreiUem-AnSE7PrW2Bv3bA3z8f00CprSR4AEmlzka5ciYFQjrbZ-tPSUx4oNEMr3c5egMORXAf5BW2Fgs8MsePzfi-XIvuvr-PKnRqB2uHODLrHJTs3VdbFeE0yhH6cPtnJvQpXQti-jNPM-Fq5p_reS_nJiRYuNbBHQcpQiSpTJMMpthAXZCkoEbvH8xkKaJGnFUuuVGbTAHx8lcSKQVtcws1EkpaTtjIv0mvu3Ke2Pd_48SfUlaZaOTxh_8nhGKNMFhXRm81RST87GL2A7dv0UPgnA0xELaF0XJxitCp6sn4hi1F9J7gLmMSL4b_W_oQpizlrzBri83wub_PiEpNaYdNG1PPxMnQ0HAJbmLEq4RSs1l9FHgfDTflFf-VFOvgE-zYn4hbmyTx7SYoqtIixRou4z8R6IcKzvde_ITK4D1OnUJUQP2N5_LrsIpa-8JdM3Nts9z_iq0sHt3JrzZC-Rktwal8IzeBLG46baSyH7zKSRmLrKflscyKJUz8j8nuiI16dPI315pUyifU7phQpuRTFOQlYa6k9eaxIXK34iyC1LzpUFUZTLd3r6jhwpPe1wFPqtuhthIuok2s-DRtjeEPuFBmKNQSAJtQzjWbRVijoyPm0-A5RQoC6xQeuGziLmaFwC0uyIAtmNYFEP2wZG31I_IZ2nz0rdjzC5CeXjG2hy_IyFdaLrCfDrKyH88VI0dFMx5jDtl_34KavJXDZUUbKdFKo7fVAmxrSYFMVsbvgNTV-hbg0VPXAwx4Q5n0rniv7SLNvwn52SafOsZWLdJ2zF0e47oraImkHgIoj4UWtNan-CVcUfvZgeTVy_6-GozIWtPgOlrXZqfC6ciGMwFxF_8GE1cTuv1csDCUGwfLtClkHrrGU_4q0ADaF4LSjvTDhDWytXfhbH0EoNE2S5OQJ5lXD2-luYnf4b2_KxJ3IlI3KJJmZopXMWyEfs1N8pWnOX5YygbFsvveq3BMIaAWoL5ZmKG8sy7Vw-cHcO5iYfEEVfB4FbDLHOvLaQxXqLHrfp5Yze733CFGbInuIG7r8d_u5t2CnxaBRzOe9CU_K5A5T6GOl-rO54075TTt1RaPUzXeRcgy5O2Op7K-59_avwyhgH5Oyso8mFqJt9lTDDSwuUARBerzchb3rxISHo2ZnAba0Y3sxjlzNO91dj0qbknegC1UgYr43scAQzFbNfY4OHk7QR0gxhy9kJJudPTIq86Ij3NBxslYIUgfa0Db46IAnJ1o3kLDPQqsGCmQXXi99hJP8jmhHjBaL35EorMG0Qc-tMhz5hfxGHO_1Lx4QCqhYC6EZHyjzAg0VtCEsgBXUfEp_3WzhgwLjYMJ27mvkGPsvttlp40DPLI9LEI34UWiDAalNbDX3m3tZhv_0mEMi13U5SHkY5-1tsoNTav3n7zTF8xG8oDgk3hXRKFRL50I7G-YAog1dRkb3jQrmR8e3Rca5nKNy2k6SKFiBUyaJWtGqmN4dvzvlX_LjJbKJpHcDDZFIv_AhPTnfNqPHzO7GYowgFksmzpMjf084qpJ3gllCYDq2zRGbMo7z0Lc76wpnW2G04_sVXiwpYZ3JlV3LM4widWOgD9KOwZPDhJ1HaG85bHp8mVU3qWEW8J3nwdiQdVUFxakyxSlu2QXyq9OXhQUwS5_pkyIBimrpbxELz-8bPtoG422zm9ydywuJirOWqHTKGwlXsmHF6aTqpk5yF4d6yWzfchFd5qbcBit_jBGbmziVjLyNpJli7YmXCAiv3J_UIITuYGy-l9bF5sG3S8jNcs5L0HyNlf7JogdFh6tAJ6A0q-7OO2yOaYdRCz3ogFTpeY8HvkooAXw968RWLatZkm8gEE75Uofo2LqYPZPmzWU8CPPONg2HwYOPiEN1C59StQHX4BedQUoKNdjQQ==
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,13 @@ public static String hash(String input) {
return SHA256.hash(input);
}

// salt is enabled only during login process, instead set it as false for saving
// passwords into DB
public static String hashPassword(String password, boolean saltEnabled) {
return PasswordManager.hashPassword(password, saltEnabled);
public static String hashPassword(String password) {
return PasswordManager.hashPassword(password);
}

// hashedPassword = db password, hashedSaltPassword = login password
public static boolean verifyPassword(String hashedPassword, String hashedSaltPassword) {
return PasswordManager.verifyPassword(hashedPassword, hashedSaltPassword);
// hashedPassword = db password, password = login password
public static boolean verifyPassword(String hashedPassword, String password) {
return PasswordManager.verifyPassword(hashedPassword, password);
}

public static void putData(File file, String secretKey, String key, String value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,56 @@

public class PasswordManager {

// salt is enabled only during login process, instead set it as false for saving passwords into DB
public static String hashPassword(String password, boolean saltEnabled) {
// salt generation
/*Random r = new SecureRandom();
byte[] salt = new byte[9];
r.nextBytes(salt);*/
String saltS = "";
String hashedPassword = "";
if (saltEnabled) {
saltS = RandomStringGenerator.generateAlphanumericString(9);//new String(salt);
hashedPassword = SHA256.hash(SHA256.hash(password) + saltS);
} else {
saltS = "000000000";
hashedPassword = SHA256.hash(password);
}

//System.out.println("hashPassword, saltS: " + saltS + " " + saltS.length() + " | hashedPassword: " + hashedPassword + " " + hashedPassword.length());
String out = saltS + hashedPassword;
/**
* Hashes a password using a randomly generated salt.
* The salt is prepended to the hash.
* The format is: salt + SHA256(SHA256(password) + salt)
*
* @param password the password to hash
* @return Base64 encoded string of salt + hash
*/
public static String hashPassword(String password) {
String salt = RandomStringGenerator.generateAlphanumericString(9);
String hashedPassword = SHA256.hash(SHA256.hash(password) + salt);

String out = salt + hashedPassword;
return Base64.getUrlEncoder().encodeToString(out.getBytes(Charset.defaultCharset()));
}

// hashedPassword = db password, hashedSaltPassword = login password
public static boolean verifyPassword(String hashedPassword, String hashedSaltPassword) {
String decodedHashedPassword = new String(Base64.getUrlDecoder().decode(hashedPassword));
String decodedHashedSaltPassword = new String(Base64.getUrlDecoder().decode(hashedSaltPassword));
String salt = decodedHashedSaltPassword.substring(0, 9);
String hashSP = decodedHashedSaltPassword.substring(9);
String hashP = decodedHashedPassword.substring(9);
/**
* Verifies a password against a stored hash.
* It supports both old (unsalted) and new (salted) hash formats.
*
* @param hashedPassword the stored hash from the database
* @param password the plaintext password to verify
* @return true if the password matches the hash, false otherwise
*/
public static boolean verifyPassword(String hashedPassword, String password) {
String decodedHashedPassword;
try {
decodedHashedPassword = new String(Base64.getUrlDecoder().decode(hashedPassword));
} catch (IllegalArgumentException e) {
// Not a valid base64 string, so it can't be a valid hash.
return false;
}

if (decodedHashedPassword.length() < 9) {
return false; // Invalid format
}

//System.out.println("verifyPassword, saltS: " + salt + " " + salt.length() + " | hashedSaltPassword: " + hashSP + " " + hashSP.length());
String hp = SHA256.hash(hashP + salt);
String salt = decodedHashedPassword.substring(0, 9);
String hashFromDB = decodedHashedPassword.substring(9);

return hashSP.equalsIgnoreCase(hp);
if (salt.equals("000000000")) {
// unsalted password in DB.
// hash is SHA256(password)
String calculatedHash = SHA256.hash(password);
return hashFromDB.equalsIgnoreCase(calculatedHash);
} else {
// salted password in DB
// hash is SHA256(SHA256(password) + salt)
String calculatedHash = SHA256.hash(SHA256.hash(password) + salt);
return hashFromDB.equalsIgnoreCase(calculatedHash);
}
}
}
22 changes: 15 additions & 7 deletions JFramework/crypto/src/test/java/crypto/CryptoTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.io.File;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class CryptoTest {
Expand Down Expand Up @@ -237,13 +238,20 @@ private void payloadExchange(File secureDataClient, File secureDataServer, Strin
@Test
public void passwordTest() {
for (String s : cryptoStrings) {
// password for DB
String dbPW = Crypto.hashPassword(s, false);

// password for login
String loginPW = Crypto.hashPassword(s, true);

assertTrue(Crypto.verifyPassword(dbPW, loginPW));
if (s == null || s.isEmpty()) {
continue; // Skip empty passwords for this test
}
// Test new hash format
String newHashedPassword = Crypto.hashPassword(s);
assertTrue("Failed to verify new password format for: '" + s + "'", Crypto.verifyPassword(newHashedPassword, s));
assertFalse("Incorrectly verified new password format with wrong password", Crypto.verifyPassword(newHashedPassword, s + "wrong"));

// Test old hash format verification
String salt = "000000000";
String hash = it.richkmeli.jframework.crypto.algorithm.SHA256.hash(s);
String oldFormatHash = java.util.Base64.getUrlEncoder().encodeToString((salt + hash).getBytes(java.nio.charset.Charset.defaultCharset()));
assertTrue("Failed to verify old password format for: '" + s + "'", Crypto.verifyPassword(oldFormatHash, s));
assertFalse("Incorrectly verified old password format with wrong password", Crypto.verifyPassword(oldFormatHash, s + "wrong"));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package it.richkmeli.jframework.crypto.controller;

import it.richkmeli.jframework.crypto.algorithm.SHA256;
import org.junit.Test;

import java.nio.charset.Charset;
import java.util.Base64;

import static org.junit.Assert.*;

public class PasswordManagerTest {

@Test
public void hashPassword() {
String password = "test_password";
String hashedPassword = PasswordManager.hashPassword(password);
assertNotNull(hashedPassword);
assertNotEquals("", hashedPassword);

// verify format: salt + hash
String decodedHashedPassword = new String(Base64.getUrlDecoder().decode(hashedPassword));
assertEquals(9 + 64, decodedHashedPassword.length());
}

@Test
public void verifyPassword_newFormat() {
String password = "test_password";
String hashedPassword = PasswordManager.hashPassword(password);
assertTrue(PasswordManager.verifyPassword(hashedPassword, password));
}

@Test
public void verifyPassword_oldFormat() {
String password = "test_password";
// Manually create an old-format hash
String salt = "000000000";
String hash = SHA256.hash(password);
String oldFormatHash = Base64.getUrlEncoder().encodeToString((salt + hash).getBytes(Charset.defaultCharset()));

assertTrue(PasswordManager.verifyPassword(oldFormatHash, password));
}

@Test
public void verifyPassword_wrongPassword() {
String password = "test_password";
String wrongPassword = "wrong_password";
String hashedPassword = PasswordManager.hashPassword(password);
assertFalse(PasswordManager.verifyPassword(hashedPassword, wrongPassword));
}

@Test
public void verifyPassword_invalidHash() {
String password = "test_password";
String invalidHash = "invalid_hash";
assertFalse(PasswordManager.verifyPassword(invalidHash, password));
}
}
Loading