static const char *mpw_passwordForSite_v3(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 ); // Calculate the site seed. // sitePasswordSeed = hmac-sha256( masterKey, siteScope . #siteName . siteName . siteCounter . #siteContext . siteContext ) size_t sitePasswordInfoSize = 0; uint8_t *sitePasswordInfo = NULL; mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteScope ); mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteName ) ) ); mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteName ); mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) ); if (siteContext) { mpw_pushInt( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteContext ) ) ); mpw_pushString( &sitePasswordInfo, &sitePasswordInfoSize, siteContext ); } if (!sitePasswordInfo) { return NULL; } const uint8_t *sitePasswordSeed = mpw_hmac_sha256( masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoSize ); mpw_free( sitePasswordInfo, sitePasswordInfoSize ); if (!sitePasswordSeed) { return NULL; } // Determine the template. const char *template = mpw_templateForType( siteType, sitePasswordSeed[0] );
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; }
static const uint8_t *mpw_masterKeyForUser_v3(const char *fullName, const char *masterPassword) { const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword ); // Calculate the master key salt. // masterKeySalt = mpKeyScope . #fullName . fullName size_t masterKeySaltSize = 0; uint8_t *masterKeySalt = NULL; mpw_pushString( &masterKeySalt, &masterKeySaltSize, mpKeyScope ); mpw_pushInt( &masterKeySalt, &masterKeySaltSize, htonl( strlen( fullName ) ) ); mpw_pushString( &masterKeySalt, &masterKeySaltSize, fullName ); if (!masterKeySalt) { return NULL; } // 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) { return NULL; } 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; }
uint8_t const *mpw_scrypt(const size_t keySize, const char *secret, const uint8_t *salt, const size_t saltSize, uint64_t N, uint32_t r, uint32_t p) { uint8_t *key = malloc( keySize ); if (!key) return NULL; if (crypto_scrypt( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize ) < 0) { mpw_free( key, keySize ); return NULL; } return key; }
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; }
void mpw_pushBuf(uint8_t **const buffer, size_t *const bufferSize, const void *pushBuffer, const size_t pushSize) { if (*bufferSize == (size_t)-1) // The buffer was marked as broken, it is missing a previous push. Abort to avoid corrupt content. return; *bufferSize += pushSize; uint8_t *resizedBuffer = realloc( *buffer, *bufferSize ); if (!resizedBuffer) { // realloc failed, we can't push. Mark the buffer as broken. mpw_free( *buffer, *bufferSize - pushSize ); *bufferSize = (size_t)-1; *buffer = NULL; return; } *buffer = resizedBuffer; uint8_t *pushDst = *buffer + *bufferSize - pushSize; memcpy( pushDst, pushBuffer, pushSize ); }
MPIdenticon mpw_identicon(const char *fullName, const char *masterPassword) { const char *leftArm[] = { "╔", "╚", "╰", "═" }; const char *rightArm[] = { "╗", "╝", "╯", "═" }; const char *body[] = { "█", "░", "▒", "▓", "☺", "☻" }; const char *accessory[] = { "◈", "◎", "◐", "◑", "◒", "◓", "☀", "☁", "☂", "☃", "", "★", "☆", "☎", "☏", "⎈", "⌂", "☘", "☢", "☣", "☕", "⌚", "⌛", "⏰", "⚡", "⛄", "⛅", "☔", "♔", "♕", "♖", "♗", "♘", "♙", "♚", "♛", "♜", "♝", "♞", "♟", "♨", "♩", "♪", "♫", "⚐", "⚑", "⚔", "⚖", "⚙", "⚠", "⌘", "⏎", "✄", "✆", "✈", "✉", "✌" }; const uint8_t *identiconSeed = NULL; if (fullName && strlen( fullName ) && masterPassword && strlen( masterPassword )) identiconSeed = mpw_hash_hmac_sha256( (const uint8_t *)masterPassword, strlen( masterPassword ), (const uint8_t *)fullName, strlen( fullName ) ); if (!identiconSeed) return (MPIdenticon){ .leftArm = "", .body = "", .rightArm = "", .accessory = "", .color=0, }; MPIdenticon identicon = { .leftArm = leftArm[identiconSeed[0] % (sizeof( leftArm ) / sizeof( leftArm[0] ))], .body = body[identiconSeed[1] % (sizeof( body ) / sizeof( body[0] ))], .rightArm = rightArm[identiconSeed[2] % (sizeof( rightArm ) / sizeof( rightArm[0] ))], .accessory = accessory[identiconSeed[3] % (sizeof( accessory ) / sizeof( accessory[0] ))], .color = (uint8_t)(identiconSeed[4] % (MPIdenticonColorLast - MPIdenticonColorFirst + 1) + MPIdenticonColorFirst), }; mpw_free( &identiconSeed, 32 ); return identicon; }
void mpw_freeString(const char *string) { mpw_free( string, strlen( string ) ); }