static const uint8_t *mpw_masterKeyForUser_v1(const char *fullName, const char *masterPassword) { const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword ); trc( "algorithm: v%d\n", 1 ); trc( "fullName: %s (%zu)\n", fullName, mpw_utf8_strlen( fullName ) ); trc( "masterPassword: %s\n", masterPassword ); trc( "key scope: %s\n", mpKeyScope ); // Calculate the master key salt. // masterKeySalt = mpKeyScope . #fullName . fullName size_t masterKeySaltSize = 0; uint8_t *masterKeySalt = NULL; mpw_push_string( &masterKeySalt, &masterKeySaltSize, mpKeyScope ); mpw_push_int( &masterKeySalt, &masterKeySaltSize, htonl( mpw_utf8_strlen( fullName ) ) ); mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName ); if (!masterKeySalt) { ftl( "Could not allocate master key salt: %d\n", errno ); return NULL; } trc( "masterKeySalt ID: %s\n", mpw_id_buf( masterKeySalt, masterKeySaltSize ) ); // Calculate the master key. // masterKey = scrypt( masterPassword, masterKeySalt ) const uint8_t *masterKey = mpw_scrypt( MP_dkLen, masterPassword, masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p ); mpw_free( masterKeySalt, masterKeySaltSize ); if (!masterKey) { ftl( "Could not allocate master key: %d\n", errno ); return NULL; } trc( "masterKey ID: %s\n", mpw_id_buf( masterKey, MP_dkLen ) ); return masterKey; }
// Algorithm version overrides. static MPMasterKey mpw_masterKey_v3( const char *fullName, const char *masterPassword) { const char *keyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication ); trc( "keyScope: %s", keyScope ); // Calculate the master key salt. trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s", keyScope, mpw_hex_l( (uint32_t)strlen( fullName ) ), fullName ); size_t masterKeySaltSize = 0; uint8_t *masterKeySalt = NULL; mpw_push_string( &masterKeySalt, &masterKeySaltSize, keyScope ); mpw_push_int( &masterKeySalt, &masterKeySaltSize, (uint32_t)strlen( fullName ) ); mpw_push_string( &masterKeySalt, &masterKeySaltSize, fullName ); if (!masterKeySalt) { err( "Could not allocate master key salt: %s", strerror( errno ) ); return NULL; } trc( " => masterKeySalt.id: %s", mpw_id_buf( masterKeySalt, masterKeySaltSize ) ); // Calculate the master key. trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%lu, r=%u, p=%u )", MP_N, MP_r, MP_p ); MPMasterKey masterKey = mpw_kdf_scrypt( MPMasterKeySize, (uint8_t *)masterPassword, strlen( masterPassword ), masterKeySalt, masterKeySaltSize, MP_N, MP_r, MP_p ); mpw_free( &masterKeySalt, masterKeySaltSize ); if (!masterKey) { err( "Could not derive master key: %s", strerror( errno ) ); return NULL; } trc( " => masterKey.id: %s", mpw_id_buf( masterKey, MPMasterKeySize ) ); return masterKey; }
MPMasterKey mpw_masterKey(const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion) { if (fullName && !strlen( fullName )) fullName = NULL; if (masterPassword && !strlen( masterPassword )) masterPassword = NULL; trc( "-- mpw_masterKey (algorithm: %u)", algorithmVersion ); trc( "fullName: %s", fullName ); trc( "masterPassword.id: %s", masterPassword? mpw_id_buf( masterPassword, strlen( masterPassword ) ): NULL ); if (!fullName || !masterPassword) return NULL; switch (algorithmVersion) { case MPAlgorithmVersion0: return mpw_masterKey_v0( fullName, masterPassword ); case MPAlgorithmVersion1: return mpw_masterKey_v1( fullName, masterPassword ); case MPAlgorithmVersion2: return mpw_masterKey_v2( fullName, masterPassword ); case MPAlgorithmVersion3: return mpw_masterKey_v3( fullName, masterPassword ); default: err( "Unsupported version: %d", algorithmVersion ); return NULL; } }
static const char *mpw_passwordForSite_v1(const uint8_t *masterKey, const char *siteName, const MPSiteType siteType, const uint32_t siteCounter, const MPSiteVariant siteVariant, const char *siteContext) { const char *siteScope = mpw_scopeForVariant( siteVariant ); trc( "algorithm: v%d\n", 1 ); trc( "siteName: %s\n", siteName ); trc( "siteCounter: %d\n", siteCounter ); trc( "siteVariant: %d\n", siteVariant ); trc( "siteType: %d\n", siteType ); trc( "site scope: %s, context: %s\n", siteScope, siteContext? "<empty>": siteContext ); trc( "seed from: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n", siteScope, mpw_hex_l( htonl( strlen( siteName ) ) ), siteName, mpw_hex_l( htonl( siteCounter ) ), mpw_hex_l( htonl( siteContext? strlen( siteContext ): 0 ) ), siteContext? "(null)": siteContext ); // Calculate the site seed. // sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext ) size_t sitePasswordInfoSize = 0; uint8_t *sitePasswordInfo = NULL; mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteScope ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_utf8_strlen( siteName ) ) ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteName ); mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) ); if (siteContext) { mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( mpw_utf8_strlen( siteContext ) ) ); mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteContext ); } if (!sitePasswordInfo) { ftl( "Could not allocate site seed info: %d\n", errno ); return NULL; } trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) ); const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize ); mpw_free( sitePasswordInfo, sitePasswordInfoSize ); if (!sitePasswordSeed) { ftl( "Could not allocate site seed: %d\n", errno ); return NULL; } trc( "sitePasswordSeed ID: %s\n", mpw_id_buf( sitePasswordSeed, 32 ) ); // Determine the template. const char *template = mpw_templateForType( siteType, sitePasswordSeed[0] );
static MPSiteKey mpw_siteKey_v2( MPMasterKey masterKey, const char *siteName, MPCounterValue siteCounter, MPKeyPurpose keyPurpose, const char *keyContext) { const char *keyScope = mpw_scopeForPurpose( keyPurpose ); trc( "keyScope: %s", keyScope ); // OTP counter value. if (siteCounter == MPCounterValueTOTP) siteCounter = ((uint32_t)time( NULL ) / MP_otp_window) * MP_otp_window; // Calculate the site seed. trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s", keyScope, mpw_hex_l( (uint32_t)strlen( siteName ) ), siteName, mpw_hex_l( siteCounter ), keyContext? mpw_hex_l( (uint32_t)strlen( keyContext ) ): NULL, keyContext ); size_t siteSaltSize = 0; uint8_t *siteSalt = NULL; mpw_push_string( &siteSalt, &siteSaltSize, keyScope ); mpw_push_int( &siteSalt, &siteSaltSize, (uint32_t)strlen( siteName ) ); mpw_push_string( &siteSalt, &siteSaltSize, siteName ); mpw_push_int( &siteSalt, &siteSaltSize, siteCounter ); if (keyContext) { mpw_push_int( &siteSalt, &siteSaltSize, (uint32_t)strlen( keyContext ) ); mpw_push_string( &siteSalt, &siteSaltSize, keyContext ); } if (!siteSalt) { err( "Could not allocate site salt: %s", strerror( errno ) ); return NULL; } trc( " => siteSalt.id: %s", mpw_id_buf( siteSalt, siteSaltSize ) ); trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", mpw_id_buf( masterKey, MPMasterKeySize ) ); MPSiteKey siteKey = mpw_hash_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize ); mpw_free( &siteSalt, siteSaltSize ); if (!siteKey) { err( "Could not derive site key: %s", strerror( errno ) ); return NULL; } trc( " => siteKey.id: %s", mpw_id_buf( siteKey, MPSiteKeySize ) ); return siteKey; }