Rename identifiers to align better with their meaning (siteVariant -> keyPurpose, siteContext -> keyContext, siteType -> passwordType).
This commit is contained in:
		@@ -44,20 +44,20 @@ MPMasterKey mpw_masterKey(const char *fullName, const char *masterPassword, cons
 | 
			
		||||
 | 
			
		||||
MPSiteKey mpw_siteKey(
 | 
			
		||||
        MPMasterKey masterKey, const char *siteName, const uint32_t siteCounter,
 | 
			
		||||
        const MPSiteVariant siteVariant, const char *siteContext, const MPAlgorithmVersion algorithmVersion) {
 | 
			
		||||
        const MPKeyPurpose keyPurpose, const char *keyContext, const MPAlgorithmVersion algorithmVersion) {
 | 
			
		||||
 | 
			
		||||
    if (!masterKey || !siteName)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    switch (algorithmVersion) {
 | 
			
		||||
        case MPAlgorithmVersion0:
 | 
			
		||||
            return mpw_siteKey_v0( masterKey, siteName, siteCounter, siteVariant, siteContext );
 | 
			
		||||
            return mpw_siteKey_v0( masterKey, siteName, siteCounter, keyPurpose, keyContext );
 | 
			
		||||
        case MPAlgorithmVersion1:
 | 
			
		||||
            return mpw_siteKey_v1( masterKey, siteName, siteCounter, siteVariant, siteContext );
 | 
			
		||||
            return mpw_siteKey_v1( masterKey, siteName, siteCounter, keyPurpose, keyContext );
 | 
			
		||||
        case MPAlgorithmVersion2:
 | 
			
		||||
            return mpw_siteKey_v2( masterKey, siteName, siteCounter, siteVariant, siteContext );
 | 
			
		||||
            return mpw_siteKey_v2( masterKey, siteName, siteCounter, keyPurpose, keyContext );
 | 
			
		||||
        case MPAlgorithmVersion3:
 | 
			
		||||
            return mpw_siteKey_v3( masterKey, siteName, siteCounter, siteVariant, siteContext );
 | 
			
		||||
            return mpw_siteKey_v3( masterKey, siteName, siteCounter, keyPurpose, keyContext );
 | 
			
		||||
        default:
 | 
			
		||||
            ftl( "Unsupported version: %d", algorithmVersion );
 | 
			
		||||
            return NULL;
 | 
			
		||||
@@ -65,20 +65,20 @@ MPSiteKey mpw_siteKey(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *mpw_sitePassword(
 | 
			
		||||
        MPSiteKey siteKey, const MPSiteType siteType, const MPAlgorithmVersion algorithmVersion) {
 | 
			
		||||
        MPSiteKey siteKey, const MPPasswordType passwordType, const MPAlgorithmVersion algorithmVersion) {
 | 
			
		||||
 | 
			
		||||
    if (!siteKey)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    switch (algorithmVersion) {
 | 
			
		||||
        case MPAlgorithmVersion0:
 | 
			
		||||
            return mpw_sitePassword_v0( siteKey, siteType );
 | 
			
		||||
            return mpw_sitePassword_v0( siteKey, passwordType );
 | 
			
		||||
        case MPAlgorithmVersion1:
 | 
			
		||||
            return mpw_sitePassword_v1( siteKey, siteType );
 | 
			
		||||
            return mpw_sitePassword_v1( siteKey, passwordType );
 | 
			
		||||
        case MPAlgorithmVersion2:
 | 
			
		||||
            return mpw_sitePassword_v2( siteKey, siteType );
 | 
			
		||||
            return mpw_sitePassword_v2( siteKey, passwordType );
 | 
			
		||||
        case MPAlgorithmVersion3:
 | 
			
		||||
            return mpw_sitePassword_v3( siteKey, siteType );
 | 
			
		||||
            return mpw_sitePassword_v3( siteKey, passwordType );
 | 
			
		||||
        default:
 | 
			
		||||
            ftl( "Unsupported version: %d", algorithmVersion );
 | 
			
		||||
            return NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -46,11 +46,11 @@ MPMasterKey mpw_masterKey(
 | 
			
		||||
 * @return A new MPSiteKeySize-byte allocated buffer or NULL if an error occurred. */
 | 
			
		||||
MPSiteKey mpw_siteKey(
 | 
			
		||||
        MPMasterKey masterKey, const char *siteName, const uint32_t siteCounter,
 | 
			
		||||
        const MPSiteVariant siteVariant, const char *siteContext, const MPAlgorithmVersion algorithmVersion);
 | 
			
		||||
        const MPKeyPurpose keyPurpose, const char *keyContext, const MPAlgorithmVersion algorithmVersion);
 | 
			
		||||
 | 
			
		||||
/** Encode a password for the site from the given site key.
 | 
			
		||||
 * @return A newly allocated string or NULL if an error occurred. */
 | 
			
		||||
const char *mpw_sitePassword(
 | 
			
		||||
        MPSiteKey siteKey, const MPSiteType siteType, const MPAlgorithmVersion algorithmVersion);
 | 
			
		||||
        MPSiteKey siteKey, const MPPasswordType passwordType, const MPAlgorithmVersion algorithmVersion);
 | 
			
		||||
 | 
			
		||||
#endif // _MPW_ALGORITHM_H
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
#define MP_p                2
 | 
			
		||||
#define MP_hash             PearlHashSHA256
 | 
			
		||||
 | 
			
		||||
static const char *mpw_templateForType_v0(MPSiteType type, uint16_t seedByte) {
 | 
			
		||||
static const char *mpw_templateForType_v0(MPPasswordType type, uint16_t seedByte) {
 | 
			
		||||
 | 
			
		||||
    size_t count = 0;
 | 
			
		||||
    const char **templates = mpw_templatesForType( type, &count );
 | 
			
		||||
@@ -45,7 +45,7 @@ static const char mpw_characterFromClass_v0(char characterClass, uint16_t seedBy
 | 
			
		||||
 | 
			
		||||
static MPMasterKey mpw_masterKeyForUser_v0(const char *fullName, const char *masterPassword) {
 | 
			
		||||
 | 
			
		||||
    const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
 | 
			
		||||
    const char *mpKeyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication );
 | 
			
		||||
    trc( "algorithm: v%d\n", 0 );
 | 
			
		||||
    trc( "fullName: %s (%zu)\n", fullName, mpw_utf8_strlen( fullName ) );
 | 
			
		||||
    trc( "masterPassword: %s\n", masterPassword );
 | 
			
		||||
@@ -79,59 +79,60 @@ static MPMasterKey mpw_masterKeyForUser_v0(const char *fullName, const char *mas
 | 
			
		||||
 | 
			
		||||
static MPSiteKey mpw_siteKey_v0(
 | 
			
		||||
        MPMasterKey masterKey, const char *siteName, const uint32_t siteCounter,
 | 
			
		||||
        const MPSiteVariant siteVariant, const char *siteContext) {
 | 
			
		||||
        const MPKeyPurpose keyPurpose, const char *keyContext) {
 | 
			
		||||
 | 
			
		||||
    const char *siteScope = mpw_scopeForVariant( siteVariant );
 | 
			
		||||
    const char *keyScope = mpw_scopeForPurpose( keyPurpose );
 | 
			
		||||
    trc( "-- mpw_siteKey_v0\n" );
 | 
			
		||||
    trc( "siteName: %s\n", siteName );
 | 
			
		||||
    trc( "siteCounter: %d\n", siteCounter );
 | 
			
		||||
    trc( "siteVariant: %d\n", siteVariant );
 | 
			
		||||
    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,
 | 
			
		||||
    trc( "keyPurpose: %d\n", keyPurpose );
 | 
			
		||||
    trc( "keyScope: %s, keyContext: %s\n", keyScope, keyContext? "<empty>": keyContext );
 | 
			
		||||
    trc( "siteKey: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n",
 | 
			
		||||
            keyScope, mpw_hex_l( htonl( strlen( siteName ) ) ), siteName,
 | 
			
		||||
            mpw_hex_l( htonl( siteCounter ) ),
 | 
			
		||||
            mpw_hex_l( htonl( siteContext? strlen( siteContext ): 0 ) ), siteContext? "(null)": siteContext );
 | 
			
		||||
            mpw_hex_l( htonl( keyContext? strlen( keyContext ): 0 ) ), keyContext? "(null)": keyContext );
 | 
			
		||||
 | 
			
		||||
    // Calculate the site seed.
 | 
			
		||||
    // siteKey = 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 );
 | 
			
		||||
    // siteKey = hmac-sha256( masterKey, keyScope . #siteName . siteName . siteCounter . #keyContext . keyContext )
 | 
			
		||||
    size_t siteSaltSize = 0;
 | 
			
		||||
    uint8_t *siteSalt = NULL;
 | 
			
		||||
    mpw_push_string( &siteSalt, &siteSaltSize, keyScope );
 | 
			
		||||
    mpw_push_int( &siteSalt, &siteSaltSize, htonl( mpw_utf8_strlen( siteName ) ) );
 | 
			
		||||
    mpw_push_string( &siteSalt, &siteSaltSize, siteName );
 | 
			
		||||
    mpw_push_int( &siteSalt, &siteSaltSize, htonl( siteCounter ) );
 | 
			
		||||
    if (keyContext) {
 | 
			
		||||
        mpw_push_int( &siteSalt, &siteSaltSize, htonl( mpw_utf8_strlen( keyContext ) ) );
 | 
			
		||||
        mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
 | 
			
		||||
    }
 | 
			
		||||
    if (!sitePasswordInfo) {
 | 
			
		||||
        ftl( "Could not allocate site seed info: %d\n", errno );
 | 
			
		||||
    if (!siteSalt || !siteSaltSize) {
 | 
			
		||||
        ftl( "Could not allocate site salt: %d\n", errno );
 | 
			
		||||
        mpw_free( siteSalt, siteSaltSize );
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
 | 
			
		||||
    trc( "siteSalt ID: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
 | 
			
		||||
 | 
			
		||||
    MPSiteKey siteKey = mpw_hmac_sha256( masterKey, MPMasterKeySize, sitePasswordInfo, sitePasswordInfoSize );
 | 
			
		||||
    mpw_free( sitePasswordInfo, sitePasswordInfoSize );
 | 
			
		||||
    MPSiteKey siteKey = mpw_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
 | 
			
		||||
    mpw_free( siteSalt, siteSaltSize );
 | 
			
		||||
    if (!siteKey) {
 | 
			
		||||
        ftl( "Could not allocate site seed: %d\n", errno );
 | 
			
		||||
        ftl( "Could not allocate site key: %d\n", errno );
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    trc( "siteKey ID: %s\n", mpw_id_buf( siteKey, 32 ) );
 | 
			
		||||
    trc( "siteKey ID: %s\n", mpw_id_buf( siteKey, MPSiteKeySize ) );
 | 
			
		||||
 | 
			
		||||
    return siteKey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *mpw_sitePassword_v0(
 | 
			
		||||
        MPSiteKey siteKey, const MPSiteType siteType) {
 | 
			
		||||
        MPSiteKey siteKey, const MPPasswordType passwordType) {
 | 
			
		||||
 | 
			
		||||
    trc( "-- mpw_sitePassword_v0\n" );
 | 
			
		||||
    trc( "siteType: %d\n", siteType );
 | 
			
		||||
    trc( "passwordType: %d\n", passwordType );
 | 
			
		||||
 | 
			
		||||
    // Determine the template.
 | 
			
		||||
    const char *_siteKey = (const char *)siteKey;
 | 
			
		||||
    const char *template = mpw_templateForType_v0( siteType, htons( _siteKey[0] ) );
 | 
			
		||||
    trc( "type %d, template: %s\n", siteType, template );
 | 
			
		||||
    if (strlen( template ) > 32) {
 | 
			
		||||
    const char *template = mpw_templateForType_v0( passwordType, htons( _siteKey[0] ) );
 | 
			
		||||
    trc( "type %d, template: %s\n", passwordType, template );
 | 
			
		||||
    if (strlen( template ) > MPSiteKeySize) {
 | 
			
		||||
        ftl( "Template too long for password seed: %lu", strlen( template ) );
 | 
			
		||||
        mpw_free( _siteKey, sizeof( _siteKey ) );
 | 
			
		||||
        return NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@
 | 
			
		||||
 | 
			
		||||
static MPMasterKey mpw_masterKeyForUser_v1(const char *fullName, const char *masterPassword) {
 | 
			
		||||
 | 
			
		||||
    const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
 | 
			
		||||
    const char *mpKeyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication );
 | 
			
		||||
    trc( "algorithm: v%d\n", 1 );
 | 
			
		||||
    trc( "fullName: %s (%zu)\n", fullName, mpw_utf8_strlen( fullName ) );
 | 
			
		||||
    trc( "masterPassword: %s\n", masterPassword );
 | 
			
		||||
@@ -63,58 +63,59 @@ static MPMasterKey mpw_masterKeyForUser_v1(const char *fullName, const char *mas
 | 
			
		||||
 | 
			
		||||
static MPSiteKey mpw_siteKey_v1(
 | 
			
		||||
        MPMasterKey masterKey, const char *siteName, const uint32_t siteCounter,
 | 
			
		||||
        const MPSiteVariant siteVariant, const char *siteContext) {
 | 
			
		||||
        const MPKeyPurpose keyPurpose, const char *keyContext) {
 | 
			
		||||
 | 
			
		||||
    const char *siteScope = mpw_scopeForVariant( siteVariant );
 | 
			
		||||
    const char *keyScope = mpw_scopeForPurpose( keyPurpose );
 | 
			
		||||
    trc( "-- mpw_siteKey_v1\n" );
 | 
			
		||||
    trc( "siteName: %s\n", siteName );
 | 
			
		||||
    trc( "siteCounter: %d\n", siteCounter );
 | 
			
		||||
    trc( "siteVariant: %d\n", siteVariant );
 | 
			
		||||
    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,
 | 
			
		||||
    trc( "keyPurpose: %d\n", keyPurpose );
 | 
			
		||||
    trc( "keyScope: %s, keyContext: %s\n", keyScope, keyContext? "<empty>": keyContext );
 | 
			
		||||
    trc( "siteKey: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n",
 | 
			
		||||
            keyScope, mpw_hex_l( htonl( strlen( siteName ) ) ), siteName,
 | 
			
		||||
            mpw_hex_l( htonl( siteCounter ) ),
 | 
			
		||||
            mpw_hex_l( htonl( siteContext? strlen( siteContext ): 0 ) ), siteContext? "(null)": siteContext );
 | 
			
		||||
            mpw_hex_l( htonl( keyContext? strlen( keyContext ): 0 ) ), keyContext? "(null)": keyContext );
 | 
			
		||||
 | 
			
		||||
    // Calculate the site seed.
 | 
			
		||||
    // siteKey = 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 );
 | 
			
		||||
    // siteKey = hmac-sha256( masterKey, keyScope . #siteName . siteName . siteCounter . #keyContext . keyContext )
 | 
			
		||||
    size_t siteSaltSize = 0;
 | 
			
		||||
    uint8_t *siteSalt = NULL;
 | 
			
		||||
    mpw_push_string( &siteSalt, &siteSaltSize, keyScope );
 | 
			
		||||
    mpw_push_int( &siteSalt, &siteSaltSize, htonl( mpw_utf8_strlen( siteName ) ) );
 | 
			
		||||
    mpw_push_string( &siteSalt, &siteSaltSize, siteName );
 | 
			
		||||
    mpw_push_int( &siteSalt, &siteSaltSize, htonl( siteCounter ) );
 | 
			
		||||
    if (keyContext) {
 | 
			
		||||
        mpw_push_int( &siteSalt, &siteSaltSize, htonl( mpw_utf8_strlen( keyContext ) ) );
 | 
			
		||||
        mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
 | 
			
		||||
    }
 | 
			
		||||
    if (!sitePasswordInfo) {
 | 
			
		||||
        ftl( "Could not allocate site seed info: %d\n", errno );
 | 
			
		||||
    if (!siteSalt || !siteSaltSize) {
 | 
			
		||||
        ftl( "Could not allocate site salt: %d\n", errno );
 | 
			
		||||
        mpw_free( siteSalt, siteSaltSize );
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
 | 
			
		||||
    trc( "siteSalt ID: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
 | 
			
		||||
 | 
			
		||||
    MPSiteKey siteKey = mpw_hmac_sha256( masterKey, MPMasterKeySize, sitePasswordInfo, sitePasswordInfoSize );
 | 
			
		||||
    mpw_free( sitePasswordInfo, sitePasswordInfoSize );
 | 
			
		||||
    MPSiteKey siteKey = mpw_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
 | 
			
		||||
    mpw_free( siteSalt, siteSaltSize );
 | 
			
		||||
    if (!siteKey) {
 | 
			
		||||
        ftl( "Could not allocate site seed: %d\n", errno );
 | 
			
		||||
        ftl( "Could not allocate site key: %d\n", errno );
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    trc( "siteKey ID: %s\n", mpw_id_buf( siteKey, 32 ) );
 | 
			
		||||
    trc( "siteKey ID: %s\n", mpw_id_buf( siteKey, MPSiteKeySize ) );
 | 
			
		||||
 | 
			
		||||
    return siteKey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *mpw_sitePassword_v1(
 | 
			
		||||
        MPSiteKey siteKey, const MPSiteType siteType) {
 | 
			
		||||
        MPSiteKey siteKey, const MPPasswordType passwordType) {
 | 
			
		||||
 | 
			
		||||
    trc( "-- mpw_sitePassword_v1\n" );
 | 
			
		||||
    trc( "siteType: %d\n", siteType );
 | 
			
		||||
    trc( "passwordType: %d\n", passwordType );
 | 
			
		||||
 | 
			
		||||
    // Determine the template.
 | 
			
		||||
    const char *template = mpw_templateForType( siteType, siteKey[0] );
 | 
			
		||||
    trc( "type %d, template: %s\n", siteType, template );
 | 
			
		||||
    if (strlen( template ) > 32) {
 | 
			
		||||
    const char *template = mpw_templateForType( passwordType, siteKey[0] );
 | 
			
		||||
    trc( "type %d, template: %s\n", passwordType, template );
 | 
			
		||||
    if (strlen( template ) > MPSiteKeySize) {
 | 
			
		||||
        ftl( "Template too long for password seed: %lu", strlen( template ) );
 | 
			
		||||
        mpw_free( siteKey, sizeof( siteKey ) );
 | 
			
		||||
        return NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@
 | 
			
		||||
 | 
			
		||||
static MPMasterKey mpw_masterKeyForUser_v2(const char *fullName, const char *masterPassword) {
 | 
			
		||||
 | 
			
		||||
    const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
 | 
			
		||||
    const char *mpKeyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication );
 | 
			
		||||
    trc( "algorithm: v%d\n", 2 );
 | 
			
		||||
    trc( "fullName: %s (%zu)\n", fullName, mpw_utf8_strlen( fullName ) );
 | 
			
		||||
    trc( "masterPassword: %s\n", masterPassword );
 | 
			
		||||
@@ -63,58 +63,59 @@ static MPMasterKey mpw_masterKeyForUser_v2(const char *fullName, const char *mas
 | 
			
		||||
 | 
			
		||||
static MPSiteKey mpw_siteKey_v2(
 | 
			
		||||
        MPMasterKey masterKey, const char *siteName, const uint32_t siteCounter,
 | 
			
		||||
        const MPSiteVariant siteVariant, const char *siteContext) {
 | 
			
		||||
        const MPKeyPurpose keyPurpose, const char *keyContext) {
 | 
			
		||||
 | 
			
		||||
    const char *siteScope = mpw_scopeForVariant( siteVariant );
 | 
			
		||||
    const char *keyScope = mpw_scopeForPurpose( keyPurpose );
 | 
			
		||||
    trc( "-- mpw_siteKey_v2\n" );
 | 
			
		||||
    trc( "siteName: %s\n", siteName );
 | 
			
		||||
    trc( "siteCounter: %d\n", siteCounter );
 | 
			
		||||
    trc( "siteVariant: %d\n", siteVariant );
 | 
			
		||||
    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,
 | 
			
		||||
    trc( "keyPurpose: %d\n", keyPurpose );
 | 
			
		||||
    trc( "keyScope: %s, keyContext: %s\n", keyScope, keyContext? "<empty>": keyContext );
 | 
			
		||||
    trc( "siteKey: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n",
 | 
			
		||||
            keyScope, mpw_hex_l( htonl( strlen( siteName ) ) ), siteName,
 | 
			
		||||
            mpw_hex_l( htonl( siteCounter ) ),
 | 
			
		||||
            mpw_hex_l( htonl( siteContext? strlen( siteContext ): 0 ) ), siteContext? "(null)": siteContext );
 | 
			
		||||
            mpw_hex_l( htonl( keyContext? strlen( keyContext ): 0 ) ), keyContext? "(null)": keyContext );
 | 
			
		||||
 | 
			
		||||
    // Calculate the site seed.
 | 
			
		||||
    // siteKey = 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( strlen( siteName ) ) );
 | 
			
		||||
    mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteName );
 | 
			
		||||
    mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) );
 | 
			
		||||
    if (siteContext) {
 | 
			
		||||
        mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteContext ) ) );
 | 
			
		||||
        mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteContext );
 | 
			
		||||
    // siteKey = hmac-sha256( masterKey, keyScope . #siteName . siteName . siteCounter . #keyContext . keyContext )
 | 
			
		||||
    size_t siteSaltSize = 0;
 | 
			
		||||
    uint8_t *siteSalt = NULL;
 | 
			
		||||
    mpw_push_string( &siteSalt, &siteSaltSize, keyScope );
 | 
			
		||||
    mpw_push_int( &siteSalt, &siteSaltSize, htonl( strlen( siteName ) ) );
 | 
			
		||||
    mpw_push_string( &siteSalt, &siteSaltSize, siteName );
 | 
			
		||||
    mpw_push_int( &siteSalt, &siteSaltSize, htonl( siteCounter ) );
 | 
			
		||||
    if (keyContext) {
 | 
			
		||||
        mpw_push_int( &siteSalt, &siteSaltSize, htonl( strlen( keyContext ) ) );
 | 
			
		||||
        mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
 | 
			
		||||
    }
 | 
			
		||||
    if (!sitePasswordInfo) {
 | 
			
		||||
        ftl( "Could not allocate site seed info: %d\n", errno );
 | 
			
		||||
    if (!siteSalt || !siteSaltSize) {
 | 
			
		||||
        ftl( "Could not allocate site salt: %d\n", errno );
 | 
			
		||||
        mpw_free( siteSalt, siteSaltSize );
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
 | 
			
		||||
    trc( "siteSalt ID: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
 | 
			
		||||
 | 
			
		||||
    const uint8_t *siteKey = mpw_hmac_sha256( masterKey, MPMasterKeySize, sitePasswordInfo, sitePasswordInfoSize );
 | 
			
		||||
    mpw_free( sitePasswordInfo, sitePasswordInfoSize );
 | 
			
		||||
    const uint8_t *siteKey = mpw_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
 | 
			
		||||
    mpw_free( siteSalt, siteSaltSize );
 | 
			
		||||
    if (!siteKey) {
 | 
			
		||||
        ftl( "Could not allocate site seed: %d\n", errno );
 | 
			
		||||
        ftl( "Could not allocate site key: %d\n", errno );
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    trc( "siteKey ID: %s\n", mpw_id_buf( siteKey, 32 ) );
 | 
			
		||||
    trc( "siteKey ID: %s\n", mpw_id_buf( siteKey, MPSiteKeySize ) );
 | 
			
		||||
 | 
			
		||||
    return siteKey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *mpw_sitePassword_v2(
 | 
			
		||||
        MPSiteKey siteKey, const MPSiteType siteType) {
 | 
			
		||||
        MPSiteKey siteKey, const MPPasswordType passwordType) {
 | 
			
		||||
 | 
			
		||||
    trc( "-- mpw_sitePassword_v2\n" );
 | 
			
		||||
    trc( "siteType: %d\n", siteType );
 | 
			
		||||
    trc( "passwordType: %d\n", passwordType );
 | 
			
		||||
 | 
			
		||||
    // Determine the template.
 | 
			
		||||
    const char *template = mpw_templateForType( siteType, siteKey[0] );
 | 
			
		||||
    trc( "type %d, template: %s\n", siteType, template );
 | 
			
		||||
    if (strlen( template ) > 32) {
 | 
			
		||||
    const char *template = mpw_templateForType( passwordType, siteKey[0] );
 | 
			
		||||
    trc( "type %d, template: %s\n", passwordType, template );
 | 
			
		||||
    if (strlen( template ) > MPSiteKeySize) {
 | 
			
		||||
        ftl( "Template too long for password seed: %lu", strlen( template ) );
 | 
			
		||||
        mpw_free( siteKey, sizeof( siteKey ) );
 | 
			
		||||
        return NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@
 | 
			
		||||
 | 
			
		||||
static MPMasterKey mpw_masterKeyForUser_v3(const char *fullName, const char *masterPassword) {
 | 
			
		||||
 | 
			
		||||
    const char *mpKeyScope = mpw_scopeForVariant( MPSiteVariantPassword );
 | 
			
		||||
    const char *mpKeyScope = mpw_scopeForPurpose( MPKeyPurposeAuthentication );
 | 
			
		||||
    trc( "-- mpw_masterKeyForUser_v3\n" );
 | 
			
		||||
    trc( "fullName: %s (%zu)\n", fullName, strlen( fullName ) );
 | 
			
		||||
    trc( "masterPassword: %s\n", masterPassword );
 | 
			
		||||
@@ -63,58 +63,59 @@ static MPMasterKey mpw_masterKeyForUser_v3(const char *fullName, const char *mas
 | 
			
		||||
 | 
			
		||||
static MPSiteKey mpw_siteKey_v3(
 | 
			
		||||
        MPMasterKey masterKey, const char *siteName, const uint32_t siteCounter,
 | 
			
		||||
        const MPSiteVariant siteVariant, const char *siteContext) {
 | 
			
		||||
        const MPKeyPurpose keyPurpose, const char *keyContext) {
 | 
			
		||||
 | 
			
		||||
    const char *siteScope = mpw_scopeForVariant( siteVariant );
 | 
			
		||||
    const char *keyScope = mpw_scopeForPurpose( keyPurpose );
 | 
			
		||||
    trc( "-- mpw_siteKey_v3\n" );
 | 
			
		||||
    trc( "siteName: %s\n", siteName );
 | 
			
		||||
    trc( "siteCounter: %d\n", siteCounter );
 | 
			
		||||
    trc( "siteVariant: %d\n", siteVariant );
 | 
			
		||||
    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,
 | 
			
		||||
    trc( "keyPurpose: %d\n", keyPurpose );
 | 
			
		||||
    trc( "keyScope: %s, keyContext: %s\n", keyScope, keyContext? "<empty>": keyContext );
 | 
			
		||||
    trc( "siteKey: hmac-sha256(masterKey, %s | %s | %s | %s | %s | %s)\n",
 | 
			
		||||
            keyScope, mpw_hex_l( htonl( strlen( siteName ) ) ), siteName,
 | 
			
		||||
            mpw_hex_l( htonl( siteCounter ) ),
 | 
			
		||||
            mpw_hex_l( htonl( siteContext? strlen( siteContext ): 0 ) ), siteContext? "(null)": siteContext );
 | 
			
		||||
            mpw_hex_l( htonl( keyContext? strlen( keyContext ): 0 ) ), keyContext? "(null)": keyContext );
 | 
			
		||||
 | 
			
		||||
    // Calculate the site seed.
 | 
			
		||||
    // siteKey = 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( strlen( siteName ) ) );
 | 
			
		||||
    mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteName );
 | 
			
		||||
    mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( siteCounter ) );
 | 
			
		||||
    if (siteContext) {
 | 
			
		||||
        mpw_push_int( &sitePasswordInfo, &sitePasswordInfoSize, htonl( strlen( siteContext ) ) );
 | 
			
		||||
        mpw_push_string( &sitePasswordInfo, &sitePasswordInfoSize, siteContext );
 | 
			
		||||
    // siteKey = hmac-sha256( masterKey, keyScope . #siteName . siteName . siteCounter . #keyContext . keyContext )
 | 
			
		||||
    size_t siteSaltSize = 0;
 | 
			
		||||
    uint8_t *siteSalt = NULL;
 | 
			
		||||
    mpw_push_string( &siteSalt, &siteSaltSize, keyScope );
 | 
			
		||||
    mpw_push_int( &siteSalt, &siteSaltSize, htonl( strlen( siteName ) ) );
 | 
			
		||||
    mpw_push_string( &siteSalt, &siteSaltSize, siteName );
 | 
			
		||||
    mpw_push_int( &siteSalt, &siteSaltSize, htonl( siteCounter ) );
 | 
			
		||||
    if (keyContext) {
 | 
			
		||||
        mpw_push_int( &siteSalt, &siteSaltSize, htonl( strlen( keyContext ) ) );
 | 
			
		||||
        mpw_push_string( &siteSalt, &siteSaltSize, keyContext );
 | 
			
		||||
    }
 | 
			
		||||
    if (!sitePasswordInfo) {
 | 
			
		||||
        ftl( "Could not allocate site seed info: %d\n", errno );
 | 
			
		||||
    if (!siteSalt) {
 | 
			
		||||
        ftl( "Could not allocate site salt: %d\n", errno );
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    trc( "sitePasswordInfo ID: %s\n", mpw_id_buf( sitePasswordInfo, sitePasswordInfoSize ) );
 | 
			
		||||
    trc( "siteSalt ID: %s\n", mpw_id_buf( siteSalt, siteSaltSize ) );
 | 
			
		||||
 | 
			
		||||
    MPSiteKey siteKey = mpw_hmac_sha256( masterKey, MPMasterKeySize, sitePasswordInfo, sitePasswordInfoSize );
 | 
			
		||||
    mpw_free( sitePasswordInfo, sitePasswordInfoSize );
 | 
			
		||||
    if (!siteKey) {
 | 
			
		||||
        ftl( "Could not allocate site seed: %d\n", errno );
 | 
			
		||||
    MPSiteKey siteKey = mpw_hmac_sha256( masterKey, MPMasterKeySize, siteSalt, siteSaltSize );
 | 
			
		||||
    mpw_free( siteSalt, siteSaltSize );
 | 
			
		||||
    if (!siteKey || !siteSaltSize) {
 | 
			
		||||
        ftl( "Could not allocate site key: %d\n", errno );
 | 
			
		||||
        mpw_free( siteSalt, siteSaltSize );
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    trc( "siteKey ID: %s\n", mpw_id_buf( siteKey, 32 ) );
 | 
			
		||||
    trc( "siteKey ID: %s\n", mpw_id_buf( siteKey, MPSiteKeySize ) );
 | 
			
		||||
 | 
			
		||||
    return siteKey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *mpw_sitePassword_v3(
 | 
			
		||||
        MPSiteKey siteKey, const MPSiteType siteType) {
 | 
			
		||||
        MPSiteKey siteKey, const MPPasswordType passwordType) {
 | 
			
		||||
 | 
			
		||||
    trc( "-- mpw_sitePassword_v3\n" );
 | 
			
		||||
    trc( "siteType: %d\n", siteType );
 | 
			
		||||
    trc( "passwordType: %d\n", passwordType );
 | 
			
		||||
 | 
			
		||||
    // Determine the template.
 | 
			
		||||
    const char *template = mpw_templateForType( siteType, siteKey[0] );
 | 
			
		||||
    trc( "type %d, template: %s\n", siteType, template );
 | 
			
		||||
    if (strlen( template ) > 32) {
 | 
			
		||||
    const char *template = mpw_templateForType( passwordType, siteKey[0] );
 | 
			
		||||
    trc( "type %d, template: %s\n", passwordType, template );
 | 
			
		||||
    if (strlen( template ) > MPSiteKeySize) {
 | 
			
		||||
        ftl( "Template too long for password seed: %lu", strlen( template ) );
 | 
			
		||||
        mpw_free( siteKey, sizeof( siteKey ) );
 | 
			
		||||
        return NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ MPMarshalledUser *mpw_marshall_user(
 | 
			
		||||
            .redacted = true,
 | 
			
		||||
 | 
			
		||||
            .avatar = 0,
 | 
			
		||||
            .defaultType = MPSiteTypeDefault,
 | 
			
		||||
            .defaultType = MPPasswordTypeDefault,
 | 
			
		||||
            .lastUsed = 0,
 | 
			
		||||
 | 
			
		||||
            .sites_count = 0,
 | 
			
		||||
@@ -49,7 +49,7 @@ MPMarshalledUser *mpw_marshall_user(
 | 
			
		||||
 | 
			
		||||
MPMarshalledSite *mpw_marshall_site(
 | 
			
		||||
        MPMarshalledUser *marshalledUser,
 | 
			
		||||
        const char *siteName, const MPSiteType siteType, const uint32_t siteCounter, const MPAlgorithmVersion algorithmVersion) {
 | 
			
		||||
        const char *siteName, const MPPasswordType siteType, const uint32_t siteCounter, const MPAlgorithmVersion algorithmVersion) {
 | 
			
		||||
 | 
			
		||||
    if (!siteName || !(marshalledUser->sites =
 | 
			
		||||
            realloc( marshalledUser->sites, sizeof( MPMarshalledSite ) * (++marshalledUser->sites_count) )))
 | 
			
		||||
@@ -170,8 +170,8 @@ static bool mpw_marshall_write_flat(
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (site.type & MPSiteTypeClassGenerated) {
 | 
			
		||||
                MPSiteKey siteKey = mpw_siteKey( masterKey, site.name, site.counter, MPSiteVariantPassword, NULL, site.algorithm );
 | 
			
		||||
            if (site.type & MPPasswordTypeClassGenerated) {
 | 
			
		||||
                MPSiteKey siteKey = mpw_siteKey( masterKey, site.name, site.counter, MPKeyPurposeAuthentication, NULL, site.algorithm );
 | 
			
		||||
                content = mpw_sitePassword( siteKey, site.type, site.algorithm );
 | 
			
		||||
                mpw_free( siteKey, MPSiteKeySize );
 | 
			
		||||
            }
 | 
			
		||||
@@ -253,8 +253,8 @@ static bool mpw_marshall_write_json(
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (site.type & MPSiteTypeClassGenerated) {
 | 
			
		||||
                MPSiteKey siteKey = mpw_siteKey( masterKey, site.name, site.counter, MPSiteVariantPassword, NULL, site.algorithm );
 | 
			
		||||
            if (site.type & MPPasswordTypeClassGenerated) {
 | 
			
		||||
                MPSiteKey siteKey = mpw_siteKey( masterKey, site.name, site.counter, MPKeyPurposeAuthentication, NULL, site.algorithm );
 | 
			
		||||
                content = mpw_sitePassword( siteKey, site.type, site.algorithm );
 | 
			
		||||
                mpw_free( siteKey, MPSiteKeySize );
 | 
			
		||||
            }
 | 
			
		||||
@@ -290,8 +290,8 @@ static bool mpw_marshall_write_json(
 | 
			
		||||
            json_object_object_add( json_site_questions, question.keyword, json_site_question );
 | 
			
		||||
 | 
			
		||||
            if (!user->redacted) {
 | 
			
		||||
                MPSiteKey siteKey = mpw_siteKey( masterKey, site.name, 1, MPSiteVariantAnswer, question.keyword, site.algorithm );
 | 
			
		||||
                const char *answer = mpw_sitePassword( siteKey, MPSiteTypeGeneratedPhrase, site.algorithm );
 | 
			
		||||
                MPSiteKey siteKey = mpw_siteKey( masterKey, site.name, 1, MPKeyPurposeRecovery, question.keyword, site.algorithm );
 | 
			
		||||
                const char *answer = mpw_sitePassword( siteKey, MPPasswordTypeGeneratedPhrase, site.algorithm );
 | 
			
		||||
                mpw_free( siteKey, MPSiteKeySize );
 | 
			
		||||
                if (answer)
 | 
			
		||||
                    json_object_object_add( json_site_question, "answer", json_object_new_string( answer ) );
 | 
			
		||||
@@ -338,7 +338,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
 | 
			
		||||
    unsigned int importFormat = 0, importAvatar = 0;
 | 
			
		||||
    char *importUserName = NULL, *importKeyID = NULL, *importDate = NULL;
 | 
			
		||||
    MPAlgorithmVersion importAlgorithm = MPAlgorithmVersionCurrent, masterKeyAlgorithm = (MPAlgorithmVersion)-1;
 | 
			
		||||
    MPSiteType importDefaultType = MPSiteTypeDefault;
 | 
			
		||||
    MPPasswordType importDefaultType = MPPasswordTypeDefault;
 | 
			
		||||
    bool headerStarted = false, headerEnded = false, importRedacted = false;
 | 
			
		||||
    for (char *endOfLine, *positionInLine = in; (endOfLine = strstr( positionInLine, "\n" )); positionInLine = endOfLine + 1) {
 | 
			
		||||
 | 
			
		||||
@@ -391,7 +391,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
 | 
			
		||||
                importAlgorithm = (MPAlgorithmVersion)importAlgorithmInt;
 | 
			
		||||
            }
 | 
			
		||||
            if (strcmp( headerName, "Default Type" ) == 0)
 | 
			
		||||
                importDefaultType = (MPSiteType)atoi( headerValue );
 | 
			
		||||
                importDefaultType = (MPPasswordType)atoi( headerValue );
 | 
			
		||||
            if (strcmp( headerName, "Passwords" ) == 0)
 | 
			
		||||
                importRedacted = strcmp( headerValue, "VISIBLE" ) != 0;
 | 
			
		||||
 | 
			
		||||
@@ -479,7 +479,7 @@ static MPMarshalledUser *mpw_marshall_read_flat(
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            MPMarshalledSite *site = mpw_marshall_site( user, siteName,
 | 
			
		||||
                    (MPSiteType)atoi( siteType ), (uint32_t)atoi( siteCounter ), siteAlgorithmInt );
 | 
			
		||||
                    (MPPasswordType)atoi( siteType ), (uint32_t)atoi( siteCounter ), siteAlgorithmInt );
 | 
			
		||||
            if (!site) {
 | 
			
		||||
                err( "Couldn't allocate a new site.\n" );
 | 
			
		||||
                return NULL;
 | 
			
		||||
@@ -565,7 +565,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
 | 
			
		||||
        *error = MPMarshallErrorIllegal;
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    MPSiteType defaultType = (MPSiteType)mpw_get_json_int( json_file, "user.default_type", MPSiteTypeDefault );
 | 
			
		||||
    MPPasswordType defaultType = (MPPasswordType)mpw_get_json_int( json_file, "user.default_type", MPPasswordTypeDefault );
 | 
			
		||||
 | 
			
		||||
    if (!fullName || !strlen( fullName )) {
 | 
			
		||||
        err( "Missing value for full name.\n" );
 | 
			
		||||
@@ -595,7 +595,7 @@ static MPMarshalledUser *mpw_marshall_read_json(
 | 
			
		||||
    json_object_iter json_site;
 | 
			
		||||
    json_object *json_sites = mpw_get_json_section( json_file, "sites" );
 | 
			
		||||
    json_object_object_foreachC( json_sites, json_site ) {
 | 
			
		||||
        MPSiteType siteType = (MPSiteType)mpw_get_json_int( json_site.val, "type", (int)user->defaultType );
 | 
			
		||||
        MPPasswordType siteType = (MPPasswordType)mpw_get_json_int( json_site.val, "type", (int)user->defaultType );
 | 
			
		||||
        uint32_t siteCounter = (uint32_t)mpw_get_json_int( json_site.val, "counter", 1 );
 | 
			
		||||
        MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)mpw_get_json_int( json_site.val, "algorithm", (int)user->algorithm );
 | 
			
		||||
        if (siteAlgorithm < MPAlgorithmVersionFirst || siteAlgorithm > MPAlgorithmVersionLast) {
 | 
			
		||||
 
 | 
			
		||||
@@ -56,7 +56,7 @@ typedef struct MPMarshalledQuestion {
 | 
			
		||||
typedef struct MPMarshalledSite {
 | 
			
		||||
    const char *name;
 | 
			
		||||
    const char *content;
 | 
			
		||||
    MPSiteType type;
 | 
			
		||||
    MPPasswordType type;
 | 
			
		||||
    uint32_t counter;
 | 
			
		||||
    MPAlgorithmVersion algorithm;
 | 
			
		||||
 | 
			
		||||
@@ -78,7 +78,7 @@ typedef struct MPMarshalledUser {
 | 
			
		||||
    bool redacted;
 | 
			
		||||
 | 
			
		||||
    unsigned int avatar;
 | 
			
		||||
    MPSiteType defaultType;
 | 
			
		||||
    MPPasswordType defaultType;
 | 
			
		||||
    time_t lastUsed;
 | 
			
		||||
 | 
			
		||||
    size_t sites_count;
 | 
			
		||||
@@ -101,7 +101,7 @@ MPMarshalledUser *mpw_marshall_user(
 | 
			
		||||
        const char *fullName, const char *masterPassword, const MPAlgorithmVersion algorithmVersion);
 | 
			
		||||
MPMarshalledSite *mpw_marshall_site(
 | 
			
		||||
        MPMarshalledUser *marshalledUser,
 | 
			
		||||
        const char *siteName, const MPSiteType siteType, const uint32_t siteCounter, const MPAlgorithmVersion algorithmVersion);
 | 
			
		||||
        const char *siteName, const MPPasswordType siteType, const uint32_t siteCounter, const MPAlgorithmVersion algorithmVersion);
 | 
			
		||||
MPMarshalledQuestion *mpw_marshal_question(
 | 
			
		||||
        MPMarshalledSite *marshalledSite, const char *keyword);
 | 
			
		||||
bool mpw_marshal_free(
 | 
			
		||||
 
 | 
			
		||||
@@ -29,54 +29,53 @@
 | 
			
		||||
#include "mpw-types.h"
 | 
			
		||||
#include "mpw-util.h"
 | 
			
		||||
 | 
			
		||||
const MPSiteType mpw_typeWithName(const char *typeName) {
 | 
			
		||||
const MPPasswordType mpw_typeWithName(const char *typeName) {
 | 
			
		||||
 | 
			
		||||
    // Lower-case and trim optionally leading "Generated" string from typeName to standardize it.
 | 
			
		||||
    size_t stdTypeNameOffset = 0;
 | 
			
		||||
    size_t stdTypeNameSize = strlen( typeName );
 | 
			
		||||
    if (strstr(typeName, "Generated" ) == typeName)
 | 
			
		||||
    if (strstr( typeName, "Generated" ) == typeName)
 | 
			
		||||
        stdTypeNameSize -= (stdTypeNameOffset = strlen( "Generated" ));
 | 
			
		||||
    char stdTypeName[stdTypeNameSize + 1];
 | 
			
		||||
    for (size_t c = 0; c < stdTypeNameSize; ++c)
 | 
			
		||||
        stdTypeName[c] = (char)tolower( typeName[c + stdTypeNameOffset] );
 | 
			
		||||
    stdTypeName[stdTypeNameSize] = '\0';
 | 
			
		||||
 | 
			
		||||
    // Find what site type is represented by the type name.
 | 
			
		||||
    if (0 == strcmp( stdTypeName, "x" ) || 0 == strcmp( stdTypeName, "max" ) || 0 == strcmp( stdTypeName, "maximum" ))
 | 
			
		||||
        return MPSiteTypeGeneratedMaximum;
 | 
			
		||||
    if (0 == strcmp( stdTypeName, "l" ) || 0 == strcmp( stdTypeName, "long" ))
 | 
			
		||||
        return MPSiteTypeGeneratedLong;
 | 
			
		||||
    if (0 == strcmp( stdTypeName, "m" ) || 0 == strcmp( stdTypeName, "med" ) || 0 == strcmp( stdTypeName, "medium" ))
 | 
			
		||||
        return MPSiteTypeGeneratedMedium;
 | 
			
		||||
    if (0 == strcmp( stdTypeName, "b" ) || 0 == strcmp( stdTypeName, "basic" ))
 | 
			
		||||
        return MPSiteTypeGeneratedBasic;
 | 
			
		||||
    if (0 == strcmp( stdTypeName, "s" ) || 0 == strcmp( stdTypeName, "short" ))
 | 
			
		||||
        return MPSiteTypeGeneratedShort;
 | 
			
		||||
    if (0 == strcmp( stdTypeName, "i" ) || 0 == strcmp( stdTypeName, "pin" ))
 | 
			
		||||
        return MPSiteTypeGeneratedPIN;
 | 
			
		||||
    if (0 == strcmp( stdTypeName, "n" ) || 0 == strcmp( stdTypeName, "name" ))
 | 
			
		||||
        return MPSiteTypeGeneratedName;
 | 
			
		||||
    if (0 == strcmp( stdTypeName, "p" ) || 0 == strcmp( stdTypeName, "phrase" ))
 | 
			
		||||
        return MPSiteTypeGeneratedPhrase;
 | 
			
		||||
    // Find what password type is represented by the type name.
 | 
			
		||||
    if (0 == strncmp( "maximum", stdTypeName, strlen( stdTypeName ) ) || 0 == strncmp( "x", stdTypeName, 1 ))
 | 
			
		||||
        return MPPasswordTypeGeneratedMaximum;
 | 
			
		||||
    if (0 == strncmp( "long", stdTypeName, strlen( stdTypeName ) ) || 0 == strncmp( "l", stdTypeName, 1 ))
 | 
			
		||||
        return MPPasswordTypeGeneratedLong;
 | 
			
		||||
    if (0 == strncmp( "medium", stdTypeName, strlen( stdTypeName ) ) || 0 == strncmp( "m", stdTypeName, 1 ))
 | 
			
		||||
        return MPPasswordTypeGeneratedMedium;
 | 
			
		||||
    if (0 == strncmp( "basic", stdTypeName, strlen( stdTypeName ) ) || 0 == strncmp( "b", stdTypeName, 1 ))
 | 
			
		||||
        return MPPasswordTypeGeneratedBasic;
 | 
			
		||||
    if (0 == strncmp( "short", stdTypeName, strlen( stdTypeName ) ) || 0 == strncmp( "s", stdTypeName, 1 ))
 | 
			
		||||
        return MPPasswordTypeGeneratedShort;
 | 
			
		||||
    if (0 == strncmp( "pin", stdTypeName, strlen( stdTypeName ) ) || 0 == strncmp( "i", stdTypeName, 1 ))
 | 
			
		||||
        return MPPasswordTypeGeneratedPIN;
 | 
			
		||||
    if (0 == strncmp( "name", stdTypeName, strlen( stdTypeName ) ) || 0 == strncmp( "n", stdTypeName, 1 ))
 | 
			
		||||
        return MPPasswordTypeGeneratedName;
 | 
			
		||||
    if (0 == strncmp( "phrase", stdTypeName, strlen( stdTypeName ) ) || 0 == strncmp( "p", stdTypeName, 1 ))
 | 
			
		||||
        return MPPasswordTypeGeneratedPhrase;
 | 
			
		||||
 | 
			
		||||
    ftl( "Not a generated type name: %s", stdTypeName );
 | 
			
		||||
    return MPSiteTypeDefault;
 | 
			
		||||
    return MPPasswordTypeDefault;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char **mpw_templatesForType(MPSiteType type, size_t *count) {
 | 
			
		||||
const char **mpw_templatesForType(MPPasswordType type, size_t *count) {
 | 
			
		||||
 | 
			
		||||
    if (!(type & MPSiteTypeClassGenerated)) {
 | 
			
		||||
    if (!(type & MPPasswordTypeClassGenerated)) {
 | 
			
		||||
        ftl( "Not a generated type: %d", type );
 | 
			
		||||
        *count = 0;
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (type) {
 | 
			
		||||
        case MPSiteTypeGeneratedMaximum: {
 | 
			
		||||
        case MPPasswordTypeGeneratedMaximum:
 | 
			
		||||
            return mpw_alloc_array( *count, const char *,
 | 
			
		||||
                    "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" );
 | 
			
		||||
        }
 | 
			
		||||
        case MPSiteTypeGeneratedLong: {
 | 
			
		||||
        case MPPasswordTypeGeneratedLong:
 | 
			
		||||
            return mpw_alloc_array( *count, const char *,
 | 
			
		||||
                    "CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno",
 | 
			
		||||
                    "CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno",
 | 
			
		||||
@@ -85,31 +84,24 @@ const char **mpw_templatesForType(MPSiteType type, size_t *count) {
 | 
			
		||||
                    "CvccnoCvccCvcv", "CvccCvccnoCvcv", "CvccCvccCvcvno",
 | 
			
		||||
                    "CvcvnoCvccCvcc", "CvcvCvccnoCvcc", "CvcvCvccCvccno",
 | 
			
		||||
                    "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" );
 | 
			
		||||
        }
 | 
			
		||||
        case MPSiteTypeGeneratedMedium: {
 | 
			
		||||
        case MPPasswordTypeGeneratedMedium:
 | 
			
		||||
            return mpw_alloc_array( *count, const char *,
 | 
			
		||||
                    "CvcnoCvc", "CvcCvcno" );
 | 
			
		||||
        }
 | 
			
		||||
        case MPSiteTypeGeneratedBasic: {
 | 
			
		||||
        case MPPasswordTypeGeneratedBasic:
 | 
			
		||||
            return mpw_alloc_array( *count, const char *,
 | 
			
		||||
                    "aaanaaan", "aannaaan", "aaannaaa" );
 | 
			
		||||
        }
 | 
			
		||||
        case MPSiteTypeGeneratedShort: {
 | 
			
		||||
        case MPPasswordTypeGeneratedShort:
 | 
			
		||||
            return mpw_alloc_array( *count, const char *,
 | 
			
		||||
                    "Cvcn" );
 | 
			
		||||
        }
 | 
			
		||||
        case MPSiteTypeGeneratedPIN: {
 | 
			
		||||
        case MPPasswordTypeGeneratedPIN:
 | 
			
		||||
            return mpw_alloc_array( *count, const char *,
 | 
			
		||||
                    "nnnn" );
 | 
			
		||||
        }
 | 
			
		||||
        case MPSiteTypeGeneratedName: {
 | 
			
		||||
        case MPPasswordTypeGeneratedName:
 | 
			
		||||
            return mpw_alloc_array( *count, const char *,
 | 
			
		||||
                    "cvccvcvcv" );
 | 
			
		||||
        }
 | 
			
		||||
        case MPSiteTypeGeneratedPhrase: {
 | 
			
		||||
        case MPPasswordTypeGeneratedPhrase:
 | 
			
		||||
            return mpw_alloc_array( *count, const char *,
 | 
			
		||||
                    "cvcc cvc cvccvcv cvc", "cvc cvccvcvcv cvcv", "cv cvccv cvc cvcvccv" );
 | 
			
		||||
        }
 | 
			
		||||
        default: {
 | 
			
		||||
            ftl( "Unknown generated type: %d", type );
 | 
			
		||||
            *count = 0;
 | 
			
		||||
@@ -118,7 +110,7 @@ const char **mpw_templatesForType(MPSiteType type, size_t *count) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *mpw_templateForType(MPSiteType type, uint8_t seedByte) {
 | 
			
		||||
const char *mpw_templateForType(MPPasswordType type, uint8_t seedByte) {
 | 
			
		||||
 | 
			
		||||
    size_t count = 0;
 | 
			
		||||
    const char **templates = mpw_templatesForType( type, &count );
 | 
			
		||||
@@ -127,39 +119,37 @@ const char *mpw_templateForType(MPSiteType type, uint8_t seedByte) {
 | 
			
		||||
    return template;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const MPSiteVariant mpw_variantWithName(const char *variantName) {
 | 
			
		||||
const MPKeyPurpose mpw_purposeWithName(const char *purposeName) {
 | 
			
		||||
 | 
			
		||||
    // Lower-case and trim optionally leading "generated" string from typeName to standardize it.
 | 
			
		||||
    size_t stdVariantNameSize = strlen( variantName );
 | 
			
		||||
    char stdVariantName[stdVariantNameSize + 1];
 | 
			
		||||
    for (size_t c = 0; c < stdVariantNameSize; ++c)
 | 
			
		||||
        stdVariantName[c] = (char)tolower( variantName[c] );
 | 
			
		||||
    stdVariantName[stdVariantNameSize] = '\0';
 | 
			
		||||
    size_t stdPurposeNameSize = strlen( purposeName );
 | 
			
		||||
    char stdPurposeName[stdPurposeNameSize + 1];
 | 
			
		||||
    for (size_t c = 0; c < stdPurposeNameSize; ++c)
 | 
			
		||||
        stdPurposeName[c] = (char)tolower( purposeName[c] );
 | 
			
		||||
    stdPurposeName[stdPurposeNameSize] = '\0';
 | 
			
		||||
 | 
			
		||||
    if (0 == strcmp( stdVariantName, "p" ) || 0 == strcmp( stdVariantName, "password" ))
 | 
			
		||||
        return MPSiteVariantPassword;
 | 
			
		||||
    if (0 == strcmp( stdVariantName, "l" ) || 0 == strcmp( stdVariantName, "login" ))
 | 
			
		||||
        return MPSiteVariantLogin;
 | 
			
		||||
    if (0 == strcmp( stdVariantName, "a" ) || 0 == strcmp( stdVariantName, "answer" ))
 | 
			
		||||
        return MPSiteVariantAnswer;
 | 
			
		||||
    if (strncmp( "authentication", stdPurposeName, strlen( stdPurposeName ) ) == 0)
 | 
			
		||||
        return MPKeyPurposeAuthentication;
 | 
			
		||||
    if (strncmp( "identification", stdPurposeName, strlen( stdPurposeName ) ) == 0)
 | 
			
		||||
        return MPKeyPurposeIdentification;
 | 
			
		||||
    if (strncmp( "recovery", stdPurposeName, strlen( stdPurposeName ) ) == 0)
 | 
			
		||||
        return MPKeyPurposeRecovery;
 | 
			
		||||
 | 
			
		||||
    ftl( "Not a variant name: %s", stdVariantName );
 | 
			
		||||
    ftl( "Not a purpose name: %s", stdPurposeName );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *mpw_scopeForVariant(MPSiteVariant variant) {
 | 
			
		||||
const char *mpw_scopeForPurpose(MPKeyPurpose purpose) {
 | 
			
		||||
 | 
			
		||||
    switch (variant) {
 | 
			
		||||
        case MPSiteVariantPassword: {
 | 
			
		||||
    switch (purpose) {
 | 
			
		||||
        case MPKeyPurposeAuthentication:
 | 
			
		||||
            return "com.lyndir.masterpassword";
 | 
			
		||||
        }
 | 
			
		||||
        case MPSiteVariantLogin: {
 | 
			
		||||
        case MPKeyPurposeIdentification:
 | 
			
		||||
            return "com.lyndir.masterpassword.login";
 | 
			
		||||
        }
 | 
			
		||||
        case MPSiteVariantAnswer: {
 | 
			
		||||
        case MPKeyPurposeRecovery:
 | 
			
		||||
            return "com.lyndir.masterpassword.answer";
 | 
			
		||||
        }
 | 
			
		||||
        default: {
 | 
			
		||||
            ftl( "Unknown variant: %d", variant );
 | 
			
		||||
            ftl( "Unknown purpose: %d", purpose );
 | 
			
		||||
            return "";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -189,6 +179,7 @@ const char *mpw_charactersInClass(char characterClass) {
 | 
			
		||||
            return " ";
 | 
			
		||||
        default: {
 | 
			
		||||
            ftl( "Unknown character class: %c", characterClass );
 | 
			
		||||
            return "";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -37,20 +37,20 @@ typedef const uint8_t *MPMasterKey;
 | 
			
		||||
typedef const uint8_t *MPSiteKey;
 | 
			
		||||
typedef const char *MPKeyID;
 | 
			
		||||
 | 
			
		||||
typedef enum( unsigned int, MPSiteVariant ) {
 | 
			
		||||
typedef enum( unsigned int, MPKeyPurpose ) {
 | 
			
		||||
    /** Generate a key for authentication. */
 | 
			
		||||
            MPSiteVariantPassword,
 | 
			
		||||
            MPKeyPurposeAuthentication,
 | 
			
		||||
    /** Generate a name for identification. */
 | 
			
		||||
            MPSiteVariantLogin,
 | 
			
		||||
    /** Generate an answer to a security question. */
 | 
			
		||||
            MPSiteVariantAnswer,
 | 
			
		||||
            MPKeyPurposeIdentification,
 | 
			
		||||
    /** Generate a recovery token. */
 | 
			
		||||
            MPKeyPurposeRecovery,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef enum( unsigned int, MPSiteTypeClass ) {
 | 
			
		||||
typedef enum( unsigned int, MPPasswordTypeClass ) {
 | 
			
		||||
    /** Generate the password. */
 | 
			
		||||
            MPSiteTypeClassGenerated = 1 << 4,
 | 
			
		||||
            MPPasswordTypeClassGenerated = 1 << 4,
 | 
			
		||||
    /** Store the password. */
 | 
			
		||||
            MPSiteTypeClassStored = 1 << 5,
 | 
			
		||||
            MPPasswordTypeClassStored = 1 << 5,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef enum( unsigned int, MPSiteFeature ) {
 | 
			
		||||
@@ -60,37 +60,47 @@ typedef enum( unsigned int, MPSiteFeature ) {
 | 
			
		||||
            MPSiteFeatureDevicePrivate = 1 << 11,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef enum( unsigned int, MPSiteType ) {
 | 
			
		||||
    MPSiteTypeGeneratedMaximum = 0x0 | MPSiteTypeClassGenerated | 0x0,
 | 
			
		||||
    MPSiteTypeGeneratedLong = 0x1 | MPSiteTypeClassGenerated | 0x0,
 | 
			
		||||
    MPSiteTypeGeneratedMedium = 0x2 | MPSiteTypeClassGenerated | 0x0,
 | 
			
		||||
    MPSiteTypeGeneratedBasic = 0x4 | MPSiteTypeClassGenerated | 0x0,
 | 
			
		||||
    MPSiteTypeGeneratedShort = 0x3 | MPSiteTypeClassGenerated | 0x0,
 | 
			
		||||
    MPSiteTypeGeneratedPIN = 0x5 | MPSiteTypeClassGenerated | 0x0,
 | 
			
		||||
    MPSiteTypeGeneratedName = 0xE | MPSiteTypeClassGenerated | 0x0,
 | 
			
		||||
    MPSiteTypeGeneratedPhrase = 0xF | MPSiteTypeClassGenerated | 0x0,
 | 
			
		||||
typedef enum( unsigned int, MPPasswordType ) {
 | 
			
		||||
    /** pg^VMAUBk5x3p%HP%i4= */
 | 
			
		||||
    MPPasswordTypeGeneratedMaximum = 0x0 | MPPasswordTypeClassGenerated | 0x0,
 | 
			
		||||
    /** BiroYena8:Kixa */
 | 
			
		||||
    MPPasswordTypeGeneratedLong = 0x1 | MPPasswordTypeClassGenerated | 0x0,
 | 
			
		||||
    /** BirSuj0- */
 | 
			
		||||
    MPPasswordTypeGeneratedMedium = 0x2 | MPPasswordTypeClassGenerated | 0x0,
 | 
			
		||||
    /** pO98MoD0 */
 | 
			
		||||
    MPPasswordTypeGeneratedBasic = 0x4 | MPPasswordTypeClassGenerated | 0x0,
 | 
			
		||||
    /** Bir8 */
 | 
			
		||||
    MPPasswordTypeGeneratedShort = 0x3 | MPPasswordTypeClassGenerated | 0x0,
 | 
			
		||||
    /** 2798 */
 | 
			
		||||
    MPPasswordTypeGeneratedPIN = 0x5 | MPPasswordTypeClassGenerated | 0x0,
 | 
			
		||||
    /** birsujano */
 | 
			
		||||
    MPPasswordTypeGeneratedName = 0xE | MPPasswordTypeClassGenerated | 0x0,
 | 
			
		||||
    /** bir yennoquce fefi */
 | 
			
		||||
    MPPasswordTypeGeneratedPhrase = 0xF | MPPasswordTypeClassGenerated | 0x0,
 | 
			
		||||
 | 
			
		||||
    MPSiteTypeStoredPersonal = 0x0 | MPSiteTypeClassStored | MPSiteFeatureExportContent,
 | 
			
		||||
    MPSiteTypeStoredDevicePrivate = 0x1 | MPSiteTypeClassStored | MPSiteFeatureDevicePrivate,
 | 
			
		||||
    /** Custom saved password. */
 | 
			
		||||
    MPPasswordTypeStoredPersonal = 0x0 | MPPasswordTypeClassStored | MPSiteFeatureExportContent,
 | 
			
		||||
    /** Custom saved password that should not be exported from the device. */
 | 
			
		||||
    MPPasswordTypeStoredDevicePrivate = 0x1 | MPPasswordTypeClassStored | MPSiteFeatureDevicePrivate,
 | 
			
		||||
 | 
			
		||||
    MPSiteTypeDefault = MPSiteTypeGeneratedLong,
 | 
			
		||||
    MPPasswordTypeDefault = MPPasswordTypeGeneratedLong,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//// Type utilities.
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @return The variant represented by the given name.
 | 
			
		||||
 * @return The purpose represented by the given name.
 | 
			
		||||
 */
 | 
			
		||||
const MPSiteVariant mpw_variantWithName(const char *variantName);
 | 
			
		||||
const MPKeyPurpose mpw_purposeWithName(const char *purposeName);
 | 
			
		||||
/**
 | 
			
		||||
 * @return An internal string containing the scope identifier to apply when encoding for the given variant.
 | 
			
		||||
 * @return An internal string containing the scope identifier to apply when encoding for the given purpose.
 | 
			
		||||
 */
 | 
			
		||||
const char *mpw_scopeForVariant(MPSiteVariant variant);
 | 
			
		||||
const char *mpw_scopeForPurpose(MPKeyPurpose purpose);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @return The type represented by the given name.
 | 
			
		||||
 */
 | 
			
		||||
const MPSiteType mpw_typeWithName(const char *typeName);
 | 
			
		||||
const MPPasswordType mpw_typeWithName(const char *typeName);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @return A newly allocated array of internal strings that express the templates to use for the given type.
 | 
			
		||||
@@ -98,12 +108,12 @@ const MPSiteType mpw_typeWithName(const char *typeName);
 | 
			
		||||
 *         If an unsupported type is given, count will be 0 and will return NULL.
 | 
			
		||||
*          The array needs to be free'ed, the strings themselves must not be free'ed or modified.
 | 
			
		||||
 */
 | 
			
		||||
const char **mpw_templatesForType(MPSiteType type, size_t *count);
 | 
			
		||||
const char **mpw_templatesForType(MPPasswordType type, size_t *count);
 | 
			
		||||
/**
 | 
			
		||||
 * @return An internal string that contains the password encoding template of the given type
 | 
			
		||||
 *         for a seed that starts with the given byte.
 | 
			
		||||
 */
 | 
			
		||||
const char *mpw_templateForType(MPSiteType type, uint8_t seedByte);
 | 
			
		||||
const char *mpw_templateForType(MPPasswordType type, uint8_t seedByte);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @return An internal string that contains all the characters that occur in the given character class.
 | 
			
		||||
 
 | 
			
		||||
@@ -288,6 +288,7 @@ static int mpw_utf8_sizeof(unsigned char utf8Byte) {
 | 
			
		||||
 | 
			
		||||
const size_t mpw_utf8_strlen(const char *utf8String) {
 | 
			
		||||
 | 
			
		||||
    // TODO: is this ever different from strlen?
 | 
			
		||||
    size_t charlen = 0;
 | 
			
		||||
    char *remainingString = (char *)utf8String;
 | 
			
		||||
    for (int charByteSize; (charByteSize = mpw_utf8_sizeof( (unsigned char)*remainingString )); remainingString += charByteSize)
 | 
			
		||||
 
 | 
			
		||||
@@ -7,8 +7,8 @@
 | 
			
		||||
        <keyID>98EEF4D1DF46D849574A82A03C3177056B15DFFCA29BB3899DE4628453675302</keyID>
 | 
			
		||||
        <siteName>masterpasswordapp.com</siteName>
 | 
			
		||||
        <siteCounter>1</siteCounter>
 | 
			
		||||
        <siteType>GeneratedLong</siteType>
 | 
			
		||||
        <siteVariant>Password</siteVariant>
 | 
			
		||||
        <passwordType>GeneratedLong</passwordType>
 | 
			
		||||
        <keyPurpose>Password</keyPurpose>
 | 
			
		||||
        <result><!-- abstract --></result>
 | 
			
		||||
    </case>
 | 
			
		||||
 | 
			
		||||
@@ -32,45 +32,45 @@
 | 
			
		||||
        <result>LiheCuwhSerz6)</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v3_loginName" parent="v3">
 | 
			
		||||
        <siteVariant>Login</siteVariant>
 | 
			
		||||
        <siteType>GeneratedName</siteType>
 | 
			
		||||
        <keyPurpose>Login</keyPurpose>
 | 
			
		||||
        <passwordType>GeneratedName</passwordType>
 | 
			
		||||
        <result>wohzaqage</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v3_securityAnswer" parent="v3">
 | 
			
		||||
        <siteVariant>Answer</siteVariant>
 | 
			
		||||
        <siteType>GeneratedPhrase</siteType>
 | 
			
		||||
        <keyPurpose>Answer</keyPurpose>
 | 
			
		||||
        <passwordType>GeneratedPhrase</passwordType>
 | 
			
		||||
        <result>xin diyjiqoja hubu</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v3_securityAnswer_context" parent="v3_securityAnswer">
 | 
			
		||||
        <siteContext>question</siteContext>
 | 
			
		||||
        <keyContext>question</keyContext>
 | 
			
		||||
        <result>xogx tem cegyiva jab</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v3_type_maximum" parent="v3">
 | 
			
		||||
        <siteType>GeneratedMaximum</siteType>
 | 
			
		||||
        <passwordType>GeneratedMaximum</passwordType>
 | 
			
		||||
        <result>W6@692^B1#&@gVdSdLZ@</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v3_type_medium" parent="v3">
 | 
			
		||||
        <siteType>GeneratedMedium</siteType>
 | 
			
		||||
        <passwordType>GeneratedMedium</passwordType>
 | 
			
		||||
        <result>Jej2$Quv</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v3_type_basic" parent="v3">
 | 
			
		||||
        <siteType>GeneratedBasic</siteType>
 | 
			
		||||
        <passwordType>GeneratedBasic</passwordType>
 | 
			
		||||
        <result>WAo2xIg6</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v3_type_short" parent="v3">
 | 
			
		||||
        <siteType>GeneratedShort</siteType>
 | 
			
		||||
        <passwordType>GeneratedShort</passwordType>
 | 
			
		||||
        <result>Jej2</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v3_type_pin" parent="v3">
 | 
			
		||||
        <siteType>GeneratedPIN</siteType>
 | 
			
		||||
        <passwordType>GeneratedPIN</passwordType>
 | 
			
		||||
        <result>7662</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v3_type_name" parent="v3">
 | 
			
		||||
        <siteType>GeneratedName</siteType>
 | 
			
		||||
        <passwordType>GeneratedName</passwordType>
 | 
			
		||||
        <result>jejraquvo</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v3_type_phrase" parent="v3">
 | 
			
		||||
        <siteType>GeneratedPhrase</siteType>
 | 
			
		||||
        <passwordType>GeneratedPhrase</passwordType>
 | 
			
		||||
        <result>jejr quv cabsibu tam</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v3_counter_ceiling" parent="v3">
 | 
			
		||||
@@ -98,45 +98,45 @@
 | 
			
		||||
        <result>LiheCuwhSerz6)</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v2_loginName" parent="v2">
 | 
			
		||||
        <siteVariant>Login</siteVariant>
 | 
			
		||||
        <siteType>GeneratedName</siteType>
 | 
			
		||||
        <keyPurpose>Login</keyPurpose>
 | 
			
		||||
        <passwordType>GeneratedName</passwordType>
 | 
			
		||||
        <result>wohzaqage</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v2_securityAnswer" parent="v2">
 | 
			
		||||
        <siteVariant>Answer</siteVariant>
 | 
			
		||||
        <siteType>GeneratedPhrase</siteType>
 | 
			
		||||
        <keyPurpose>Answer</keyPurpose>
 | 
			
		||||
        <passwordType>GeneratedPhrase</passwordType>
 | 
			
		||||
        <result>xin diyjiqoja hubu</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v2_securityAnswer_context" parent="v2_securityAnswer">
 | 
			
		||||
        <siteContext>question</siteContext>
 | 
			
		||||
        <keyContext>question</keyContext>
 | 
			
		||||
        <result>xogx tem cegyiva jab</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v2_type_maximum" parent="v2">
 | 
			
		||||
        <siteType>GeneratedMaximum</siteType>
 | 
			
		||||
        <passwordType>GeneratedMaximum</passwordType>
 | 
			
		||||
        <result>W6@692^B1#&@gVdSdLZ@</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v2_type_medium" parent="v2">
 | 
			
		||||
        <siteType>GeneratedMedium</siteType>
 | 
			
		||||
        <passwordType>GeneratedMedium</passwordType>
 | 
			
		||||
        <result>Jej2$Quv</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v2_type_basic" parent="v2">
 | 
			
		||||
        <siteType>GeneratedBasic</siteType>
 | 
			
		||||
        <passwordType>GeneratedBasic</passwordType>
 | 
			
		||||
        <result>WAo2xIg6</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v2_type_short" parent="v2">
 | 
			
		||||
        <siteType>GeneratedShort</siteType>
 | 
			
		||||
        <passwordType>GeneratedShort</passwordType>
 | 
			
		||||
        <result>Jej2</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v2_type_pin" parent="v2">
 | 
			
		||||
        <siteType>GeneratedPIN</siteType>
 | 
			
		||||
        <passwordType>GeneratedPIN</passwordType>
 | 
			
		||||
        <result>7662</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v2_type_name" parent="v2">
 | 
			
		||||
        <siteType>GeneratedName</siteType>
 | 
			
		||||
        <passwordType>GeneratedName</passwordType>
 | 
			
		||||
        <result>jejraquvo</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v2_type_phrase" parent="v2">
 | 
			
		||||
        <siteType>GeneratedPhrase</siteType>
 | 
			
		||||
        <passwordType>GeneratedPhrase</passwordType>
 | 
			
		||||
        <result>jejr quv cabsibu tam</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v2_counter_ceiling" parent="v2">
 | 
			
		||||
@@ -164,45 +164,45 @@
 | 
			
		||||
        <result>WawiYarp2@Kodh</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v1_loginName" parent="v1">
 | 
			
		||||
        <siteVariant>Login</siteVariant>
 | 
			
		||||
        <siteType>GeneratedName</siteType>
 | 
			
		||||
        <keyPurpose>Login</keyPurpose>
 | 
			
		||||
        <passwordType>GeneratedName</passwordType>
 | 
			
		||||
        <result>wohzaqage</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v1_securityAnswer" parent="v1">
 | 
			
		||||
        <siteVariant>Answer</siteVariant>
 | 
			
		||||
        <siteType>GeneratedPhrase</siteType>
 | 
			
		||||
        <keyPurpose>Answer</keyPurpose>
 | 
			
		||||
        <passwordType>GeneratedPhrase</passwordType>
 | 
			
		||||
        <result>xin diyjiqoja hubu</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v1_securityAnswer_context" parent="v1_securityAnswer">
 | 
			
		||||
        <siteContext>question</siteContext>
 | 
			
		||||
        <keyContext>question</keyContext>
 | 
			
		||||
        <result>xogx tem cegyiva jab</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v1_type_maximum" parent="v1">
 | 
			
		||||
        <siteType>GeneratedMaximum</siteType>
 | 
			
		||||
        <passwordType>GeneratedMaximum</passwordType>
 | 
			
		||||
        <result>W6@692^B1#&@gVdSdLZ@</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v1_type_medium" parent="v1">
 | 
			
		||||
        <siteType>GeneratedMedium</siteType>
 | 
			
		||||
        <passwordType>GeneratedMedium</passwordType>
 | 
			
		||||
        <result>Jej2$Quv</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v1_type_basic" parent="v1">
 | 
			
		||||
        <siteType>GeneratedBasic</siteType>
 | 
			
		||||
        <passwordType>GeneratedBasic</passwordType>
 | 
			
		||||
        <result>WAo2xIg6</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v1_type_short" parent="v1">
 | 
			
		||||
        <siteType>GeneratedShort</siteType>
 | 
			
		||||
        <passwordType>GeneratedShort</passwordType>
 | 
			
		||||
        <result>Jej2</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v1_type_pin" parent="v1">
 | 
			
		||||
        <siteType>GeneratedPIN</siteType>
 | 
			
		||||
        <passwordType>GeneratedPIN</passwordType>
 | 
			
		||||
        <result>7662</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v1_type_name" parent="v1">
 | 
			
		||||
        <siteType>GeneratedName</siteType>
 | 
			
		||||
        <passwordType>GeneratedName</passwordType>
 | 
			
		||||
        <result>jejraquvo</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v1_type_phrase" parent="v1">
 | 
			
		||||
        <siteType>GeneratedPhrase</siteType>
 | 
			
		||||
        <passwordType>GeneratedPhrase</passwordType>
 | 
			
		||||
        <result>jejr quv cabsibu tam</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v1_counter_ceiling" parent="v1">
 | 
			
		||||
@@ -230,45 +230,45 @@
 | 
			
		||||
        <result>HahiVana2@Nole</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v0_loginName" parent="v0">
 | 
			
		||||
        <siteVariant>Login</siteVariant>
 | 
			
		||||
        <siteType>GeneratedName</siteType>
 | 
			
		||||
        <keyPurpose>Login</keyPurpose>
 | 
			
		||||
        <passwordType>GeneratedName</passwordType>
 | 
			
		||||
        <result>lozwajave</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v0_securityAnswer" parent="v0">
 | 
			
		||||
        <siteVariant>Answer</siteVariant>
 | 
			
		||||
        <siteType>GeneratedPhrase</siteType>
 | 
			
		||||
        <keyPurpose>Answer</keyPurpose>
 | 
			
		||||
        <passwordType>GeneratedPhrase</passwordType>
 | 
			
		||||
        <result>miy lirfijoja dubu</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v0_securityAnswer_context" parent="v0_securityAnswer">
 | 
			
		||||
        <siteContext>question</siteContext>
 | 
			
		||||
        <keyContext>question</keyContext>
 | 
			
		||||
        <result>movm bex gevrica jaf</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v0_type_maximum" parent="v0">
 | 
			
		||||
        <siteType>GeneratedMaximum</siteType>
 | 
			
		||||
        <passwordType>GeneratedMaximum</passwordType>
 | 
			
		||||
        <result>w1!3bA3icmRAc)SS@lwl</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v0_type_medium" parent="v0">
 | 
			
		||||
        <siteType>GeneratedMedium</siteType>
 | 
			
		||||
        <passwordType>GeneratedMedium</passwordType>
 | 
			
		||||
        <result>Fej7]Jug</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v0_type_basic" parent="v0">
 | 
			
		||||
        <siteType>GeneratedBasic</siteType>
 | 
			
		||||
        <passwordType>GeneratedBasic</passwordType>
 | 
			
		||||
        <result>wvH7irC1</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v0_type_short" parent="v0">
 | 
			
		||||
        <siteType>GeneratedShort</siteType>
 | 
			
		||||
        <passwordType>GeneratedShort</passwordType>
 | 
			
		||||
        <result>Fej7</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v0_type_pin" parent="v0">
 | 
			
		||||
        <siteType>GeneratedPIN</siteType>
 | 
			
		||||
        <passwordType>GeneratedPIN</passwordType>
 | 
			
		||||
        <result>2117</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v0_type_name" parent="v0">
 | 
			
		||||
        <siteType>GeneratedName</siteType>
 | 
			
		||||
        <passwordType>GeneratedName</passwordType>
 | 
			
		||||
        <result>fejrajugo</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v0_type_phrase" parent="v0">
 | 
			
		||||
        <siteType>GeneratedPhrase</siteType>
 | 
			
		||||
        <passwordType>GeneratedPhrase</passwordType>
 | 
			
		||||
        <result>fejr jug gabsibu bax</result>
 | 
			
		||||
    </case>
 | 
			
		||||
    <case id="v0_counter_ceiling" parent="v0">
 | 
			
		||||
 
 | 
			
		||||
@@ -331,20 +331,20 @@ static NSOperationQueue *_mpwQueue = nil;
 | 
			
		||||
- (NSString *)generateLoginForSiteNamed:(NSString *)name usingKey:(MPKey *)key {
 | 
			
		||||
 | 
			
		||||
    return [self generateContentForSiteNamed:name ofType:MPSiteTypeGeneratedName withCounter:1
 | 
			
		||||
                                     variant:MPSiteVariantLogin context:nil usingKey:key];
 | 
			
		||||
                                     variant:MPKeyPurposeIdentification context:nil usingKey:key];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSString *)generatePasswordForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
 | 
			
		||||
                                  usingKey:(MPKey *)key {
 | 
			
		||||
 | 
			
		||||
    return [self generateContentForSiteNamed:name ofType:type withCounter:counter
 | 
			
		||||
                                     variant:MPSiteVariantPassword context:nil usingKey:key];
 | 
			
		||||
                                     variant:MPKeyPurposeAuthentication context:nil usingKey:key];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSString *)generateAnswerForSiteNamed:(NSString *)name onQuestion:(NSString *)question usingKey:(MPKey *)key {
 | 
			
		||||
 | 
			
		||||
    return [self generateContentForSiteNamed:name ofType:MPSiteTypeGeneratedPhrase withCounter:1
 | 
			
		||||
                                     variant:MPSiteVariantAnswer context:question usingKey:key];
 | 
			
		||||
                                     variant:MPKeyPurposeRecovery context:question usingKey:key];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSString *)generateContentForSiteNamed:(NSString *)name ofType:(MPSiteType)type withCounter:(NSUInteger)counter
 | 
			
		||||
 
 | 
			
		||||
@@ -52,9 +52,9 @@ int main(int argc, char *const argv[]) {
 | 
			
		||||
    const char *masterPassword = "banana colored duckling";
 | 
			
		||||
    const char *siteName = "masterpasswordapp.com";
 | 
			
		||||
    const uint32_t siteCounter = 1;
 | 
			
		||||
    const MPSiteType siteType = MPSiteTypeDefault;
 | 
			
		||||
    const MPSiteVariant siteVariant = MPSiteVariantPassword;
 | 
			
		||||
    const char *siteContext = NULL;
 | 
			
		||||
    const MPPasswordType passwordType = MPPasswordTypeDefault;
 | 
			
		||||
    const MPKeyPurpose keyPurpose = MPKeyPurposeAuthentication;
 | 
			
		||||
    const char *keyContext = NULL;
 | 
			
		||||
    struct timeval startTime;
 | 
			
		||||
    unsigned int iterations;
 | 
			
		||||
    float percent;
 | 
			
		||||
@@ -112,9 +112,9 @@ int main(int argc, char *const argv[]) {
 | 
			
		||||
            ftl( "Could not allocate master key: %d\n", errno );
 | 
			
		||||
 | 
			
		||||
        MPSiteKey siteKey = mpw_siteKey(
 | 
			
		||||
                masterKey, siteName, siteCounter, siteVariant, siteContext, MPAlgorithmVersionCurrent );
 | 
			
		||||
                masterKey, siteName, siteCounter, keyPurpose, keyContext, MPAlgorithmVersionCurrent );
 | 
			
		||||
        free( (void *)mpw_sitePassword(
 | 
			
		||||
                siteKey, siteType, MPAlgorithmVersionCurrent ) );
 | 
			
		||||
                siteKey, passwordType, MPAlgorithmVersionCurrent ) );
 | 
			
		||||
        free( (void *)masterKey );
 | 
			
		||||
        free( (void *)siteKey );
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,20 +16,18 @@
 | 
			
		||||
#include "mpw-marshall.h"
 | 
			
		||||
 | 
			
		||||
#define MP_env_fullName     "MP_FULLNAME"
 | 
			
		||||
#define MP_env_siteType     "MP_SITETYPE"
 | 
			
		||||
#define MP_env_siteCounter  "MP_SITECOUNTER"
 | 
			
		||||
#define MP_env_algorithm    "MP_ALGORITHM"
 | 
			
		||||
 | 
			
		||||
static void usage() {
 | 
			
		||||
 | 
			
		||||
    inf( ""
 | 
			
		||||
            "Usage: mpw [-u name] [-t type] [-c counter] [-a algorithm] [-V variant] [-C context] [-v|-q] [-h] site\n\n" );
 | 
			
		||||
            "Usage: mpw [-u name] [-t type] [-c counter] [-a algorithm] [-p purpose] [-C context] [-v|-q] [-h] site\n\n" );
 | 
			
		||||
    inf( ""
 | 
			
		||||
            "    -u name      Specify the full name of the user.\n"
 | 
			
		||||
            "                 Defaults to %s in env or prompts.\n\n", MP_env_fullName );
 | 
			
		||||
    inf( ""
 | 
			
		||||
            "    -t type      Specify the password's template.\n"
 | 
			
		||||
            "                 Defaults to %s in env or 'long' for password, 'name' for login.\n"
 | 
			
		||||
            "                 Defaults to 'long' for auth, 'name' for ident and 'phrase' for recovery.\n"
 | 
			
		||||
            "                     x, max, maximum | 20 characters, contains symbols.\n"
 | 
			
		||||
            "                     l, long         | Copy-friendly, 14 characters, contains symbols.\n"
 | 
			
		||||
            "                     m, med, medium  | Copy-friendly, 8 characters, contains symbols.\n"
 | 
			
		||||
@@ -37,26 +35,25 @@ static void usage() {
 | 
			
		||||
            "                     s, short        | Copy-friendly, 4 characters, no symbols.\n"
 | 
			
		||||
            "                     i, pin          | 4 numbers.\n"
 | 
			
		||||
            "                     n, name         | 9 letter name.\n"
 | 
			
		||||
            "                     p, phrase       | 20 character sentence.\n\n", MP_env_siteType );
 | 
			
		||||
            "                     p, phrase       | 20 character sentence.\n\n" );
 | 
			
		||||
    inf( ""
 | 
			
		||||
            "    -c counter   The value of the counter.\n"
 | 
			
		||||
            "                 Defaults to %s in env or 1.\n\n", MP_env_siteCounter );
 | 
			
		||||
            "                 Defaults to 1.\n\n" );
 | 
			
		||||
    inf( ""
 | 
			
		||||
            "    -a version   The algorithm version to use.\n"
 | 
			
		||||
            "                 Defaults to %s in env or %d.\n\n", MP_env_algorithm, MPAlgorithmVersionCurrent );
 | 
			
		||||
    inf( ""
 | 
			
		||||
            "    -V variant   The kind of content to generate.\n"
 | 
			
		||||
            "    -p purpose   The purpose of the generated token.\n"
 | 
			
		||||
            "                 Defaults to 'password'.\n"
 | 
			
		||||
            "                     p, password | The password to log in with.\n"
 | 
			
		||||
            "                     l, login    | The username to log in as.\n"
 | 
			
		||||
            "                     a, answer   | The answer to a security question.\n\n" );
 | 
			
		||||
            "                     a, auth     | An authentication token such as a password.\n"
 | 
			
		||||
            "                     i, ident    | An identification token such as a username.\n"
 | 
			
		||||
            "                     r, rec      | A recovery token such as a security answer.\n\n" );
 | 
			
		||||
    inf( ""
 | 
			
		||||
            "    -C context   A variant-specific context.\n"
 | 
			
		||||
            "    -C context   A purpose-specific context.\n"
 | 
			
		||||
            "                 Defaults to empty.\n"
 | 
			
		||||
            "                  -V p, password | Doesn't currently use a context.\n"
 | 
			
		||||
            "                  -V l, login    | Doesn't currently use a context.\n"
 | 
			
		||||
            "                  -V a, answer   | Empty for a universal site answer or\n"
 | 
			
		||||
            "                                 | the most significant word(s) of the question.\n\n" );
 | 
			
		||||
            "                  -p a, auth     | -\n"
 | 
			
		||||
            "                  -p i, ident    | -\n"
 | 
			
		||||
            "                  -p r, rec      | Most significant word in security question.\n\n" );
 | 
			
		||||
    inf( ""
 | 
			
		||||
            "    -v           Increase output verbosity (can be repeated).\n\n" );
 | 
			
		||||
    inf( ""
 | 
			
		||||
@@ -64,10 +61,8 @@ static void usage() {
 | 
			
		||||
    inf( ""
 | 
			
		||||
            "    ENVIRONMENT\n\n"
 | 
			
		||||
            "        %-14s | The full name of the user (see -u).\n"
 | 
			
		||||
            "        %-14s | The default password template (see -t).\n"
 | 
			
		||||
            "        %-14s | The default counter value (see -c).\n"
 | 
			
		||||
            "        %-14s | The default algorithm version (see -a).\n\n",
 | 
			
		||||
            MP_env_fullName, MP_env_siteType, MP_env_siteCounter, MP_env_algorithm );
 | 
			
		||||
            MP_env_fullName, MP_env_algorithm );
 | 
			
		||||
    exit( 0 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -111,16 +106,15 @@ static char *getline_prompt(const char *prompt) {
 | 
			
		||||
int main(int argc, char *const argv[]) {
 | 
			
		||||
 | 
			
		||||
    // Master Password defaults.
 | 
			
		||||
    const char *fullName = NULL, *masterPassword = NULL, *siteName = NULL;
 | 
			
		||||
    MPSiteType siteType = MPSiteTypeDefault;
 | 
			
		||||
    MPSiteVariant siteVariant = MPSiteVariantPassword;
 | 
			
		||||
    const char *fullName = NULL, *masterPassword = NULL, *siteName = NULL, *keyContext = NULL;
 | 
			
		||||
    MPPasswordType passwordType = MPPasswordTypeDefault;
 | 
			
		||||
    MPKeyPurpose keyPurpose = MPKeyPurposeAuthentication;
 | 
			
		||||
    MPAlgorithmVersion algorithmVersion = MPAlgorithmVersionCurrent;
 | 
			
		||||
    uint32_t siteCounter = 1;
 | 
			
		||||
 | 
			
		||||
    // Read the environment.
 | 
			
		||||
    const char *fullNameArg = getenv( MP_env_fullName ), *masterPasswordArg = NULL, *siteNameArg = NULL;
 | 
			
		||||
    const char *siteTypeArg = getenv( MP_env_siteType ), *siteVariantArg = NULL, *siteContextArg = NULL;
 | 
			
		||||
    const char *siteCounterArg = getenv( MP_env_siteCounter );
 | 
			
		||||
    const char *passwordTypeArg = NULL, *keyPurposeArg = NULL, *keyContextArg = NULL, *siteCounterArg = NULL;
 | 
			
		||||
    const char *algorithmVersionArg = getenv( MP_env_algorithm );
 | 
			
		||||
 | 
			
		||||
    // Read the command-line options.
 | 
			
		||||
@@ -134,19 +128,19 @@ int main(int argc, char *const argv[]) {
 | 
			
		||||
                masterPasswordArg = optarg;
 | 
			
		||||
                break;
 | 
			
		||||
            case 't':
 | 
			
		||||
                siteTypeArg = optarg;
 | 
			
		||||
                passwordTypeArg = optarg;
 | 
			
		||||
                break;
 | 
			
		||||
            case 'c':
 | 
			
		||||
                siteCounterArg = optarg;
 | 
			
		||||
                break;
 | 
			
		||||
            case 'V':
 | 
			
		||||
                siteVariantArg = optarg;
 | 
			
		||||
            case 'p':
 | 
			
		||||
                keyPurposeArg = optarg;
 | 
			
		||||
                break;
 | 
			
		||||
            case 'a':
 | 
			
		||||
                algorithmVersionArg = optarg;
 | 
			
		||||
                break;
 | 
			
		||||
            case 'C':
 | 
			
		||||
                siteContextArg = optarg;
 | 
			
		||||
                keyContextArg = optarg;
 | 
			
		||||
                break;
 | 
			
		||||
            case 'v':
 | 
			
		||||
                ++mpw_verbosity;
 | 
			
		||||
@@ -183,9 +177,9 @@ int main(int argc, char *const argv[]) {
 | 
			
		||||
    fullNameArg = fullNameArg && strlen( fullNameArg )? fullNameArg: NULL;
 | 
			
		||||
    masterPasswordArg = masterPasswordArg && strlen( masterPasswordArg )? masterPasswordArg: NULL;
 | 
			
		||||
    siteNameArg = siteNameArg && strlen( siteNameArg )? siteNameArg: NULL;
 | 
			
		||||
    siteTypeArg = siteTypeArg && strlen( siteTypeArg )? siteTypeArg: NULL;
 | 
			
		||||
    siteVariantArg = siteVariantArg && strlen( siteVariantArg )? siteVariantArg: NULL;
 | 
			
		||||
    siteContextArg = siteContextArg && strlen( siteContextArg )? siteContextArg: NULL;
 | 
			
		||||
    passwordTypeArg = passwordTypeArg && strlen( passwordTypeArg )? passwordTypeArg: NULL;
 | 
			
		||||
    keyPurposeArg = keyPurposeArg && strlen( keyPurposeArg )? keyPurposeArg: NULL;
 | 
			
		||||
    keyContextArg = keyContextArg && strlen( keyContextArg )? keyContextArg: NULL;
 | 
			
		||||
    siteCounterArg = siteCounterArg && strlen( siteCounterArg )? siteCounterArg: NULL;
 | 
			
		||||
    algorithmVersionArg = algorithmVersionArg && strlen( algorithmVersionArg )? algorithmVersionArg: NULL;
 | 
			
		||||
 | 
			
		||||
@@ -239,11 +233,11 @@ int main(int argc, char *const argv[]) {
 | 
			
		||||
            fullName = strdup( user->name );
 | 
			
		||||
            masterPassword = strdup( user->masterPassword );
 | 
			
		||||
            algorithmVersion = user->algorithm;
 | 
			
		||||
            siteType = user->defaultType;
 | 
			
		||||
            passwordType = user->defaultType;
 | 
			
		||||
            for (size_t s = 0; s < user->sites_count; ++s) {
 | 
			
		||||
                MPMarshalledSite site = user->sites[s];
 | 
			
		||||
                if (strcmp( siteName, site.name ) == 0) {
 | 
			
		||||
                    siteType = site.type;
 | 
			
		||||
                    passwordType = site.type;
 | 
			
		||||
                    siteCounter = site.counter;
 | 
			
		||||
                    algorithmVersion = site.algorithm;
 | 
			
		||||
                    break;
 | 
			
		||||
@@ -285,14 +279,16 @@ int main(int argc, char *const argv[]) {
 | 
			
		||||
            ftl( "Invalid site counter: %s\n", siteCounterArg );
 | 
			
		||||
        siteCounter = (uint32_t)siteCounterInt;
 | 
			
		||||
    }
 | 
			
		||||
    if (siteVariantArg)
 | 
			
		||||
        siteVariant = mpw_variantWithName( siteVariantArg );
 | 
			
		||||
    if (siteVariant == MPSiteVariantLogin)
 | 
			
		||||
        siteType = MPSiteTypeGeneratedName;
 | 
			
		||||
    if (siteVariant == MPSiteVariantAnswer)
 | 
			
		||||
        siteType = MPSiteTypeGeneratedPhrase;
 | 
			
		||||
    if (siteTypeArg)
 | 
			
		||||
        siteType = mpw_typeWithName( siteTypeArg );
 | 
			
		||||
    if (keyPurposeArg)
 | 
			
		||||
        keyPurpose = mpw_purposeWithName( keyPurposeArg );
 | 
			
		||||
    if (keyPurpose == MPKeyPurposeIdentification)
 | 
			
		||||
        passwordType = MPPasswordTypeGeneratedName;
 | 
			
		||||
    if (keyPurpose == MPKeyPurposeRecovery)
 | 
			
		||||
        passwordType = MPPasswordTypeGeneratedPhrase;
 | 
			
		||||
    if (passwordTypeArg)
 | 
			
		||||
        passwordType = mpw_typeWithName( passwordTypeArg );
 | 
			
		||||
    if (keyContextArg)
 | 
			
		||||
        keyContext = strdup( keyContextArg );
 | 
			
		||||
 | 
			
		||||
    // Summarize operation.
 | 
			
		||||
    const char *identicon = mpw_identicon( fullName, masterPassword );
 | 
			
		||||
@@ -303,7 +299,7 @@ int main(int argc, char *const argv[]) {
 | 
			
		||||
    trc( "masterPassword   : %s\n", masterPassword );
 | 
			
		||||
    dbg( "identicon        : %s\n", identicon );
 | 
			
		||||
    dbg( "siteName         : %s\n", siteName );
 | 
			
		||||
    dbg( "siteType         : %u\n", siteType );
 | 
			
		||||
    dbg( "passwordType     : %u\n", passwordType );
 | 
			
		||||
    dbg( "algorithmVersion : %u\n", algorithmVersion );
 | 
			
		||||
    dbg( "siteCounter      : %u\n", siteCounter );
 | 
			
		||||
    dbg( "-----------------\n\n" );
 | 
			
		||||
@@ -318,11 +314,12 @@ int main(int argc, char *const argv[]) {
 | 
			
		||||
    if (!masterKey)
 | 
			
		||||
        ftl( "Couldn't derive master key." );
 | 
			
		||||
 | 
			
		||||
    MPSiteKey siteKey = mpw_siteKey( masterKey, siteName, siteCounter, siteVariant, siteContextArg, algorithmVersion );
 | 
			
		||||
    const char *sitePassword = mpw_sitePassword(siteKey, siteType, algorithmVersion );
 | 
			
		||||
    MPSiteKey siteKey = mpw_siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
 | 
			
		||||
    const char *sitePassword = mpw_sitePassword(siteKey, passwordType, algorithmVersion );
 | 
			
		||||
    mpw_free( masterKey, MPMasterKeySize );
 | 
			
		||||
    mpw_free( siteKey, MPSiteKeySize );
 | 
			
		||||
    mpw_free_string( siteName );
 | 
			
		||||
    mpw_free_string( keyContext );
 | 
			
		||||
    if (!sitePassword)
 | 
			
		||||
        ftl( "Couldn't derive site password." );
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,3 @@
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
@@ -30,13 +28,13 @@ int main(int argc, char *const argv[]) {
 | 
			
		||||
        xmlChar *keyID = mpw_xmlTestCaseString( testCase, "keyID" );
 | 
			
		||||
        xmlChar *siteName = mpw_xmlTestCaseString( testCase, "siteName" );
 | 
			
		||||
        uint32_t siteCounter = mpw_xmlTestCaseInteger( testCase, "siteCounter" );
 | 
			
		||||
        xmlChar *siteTypeString = mpw_xmlTestCaseString( testCase, "siteType" );
 | 
			
		||||
        xmlChar *siteVariantString = mpw_xmlTestCaseString( testCase, "siteVariant" );
 | 
			
		||||
        xmlChar *siteContext = mpw_xmlTestCaseString( testCase, "siteContext" );
 | 
			
		||||
        xmlChar *passwordTypeString = mpw_xmlTestCaseString( testCase, "passwordType" );
 | 
			
		||||
        xmlChar *keyPurposeString = mpw_xmlTestCaseString( testCase, "keyPurpose" );
 | 
			
		||||
        xmlChar *keyContext = mpw_xmlTestCaseString( testCase, "keyContext" );
 | 
			
		||||
        xmlChar *result = mpw_xmlTestCaseString( testCase, "result" );
 | 
			
		||||
 | 
			
		||||
        MPSiteType siteType = mpw_typeWithName( (char *)siteTypeString );
 | 
			
		||||
        MPSiteVariant siteVariant = mpw_variantWithName( (char *)siteVariantString );
 | 
			
		||||
        MPPasswordType siteType = mpw_typeWithName( (char *)passwordTypeString );
 | 
			
		||||
        MPKeyPurpose siteVariant = mpw_purposeWithName( (char *)keyPurposeString );
 | 
			
		||||
 | 
			
		||||
        // Run the test case.
 | 
			
		||||
        fprintf( stdout, "test case %s... ", id );
 | 
			
		||||
@@ -53,7 +51,7 @@ int main(int argc, char *const argv[]) {
 | 
			
		||||
 | 
			
		||||
        // 2. calculate the site password.
 | 
			
		||||
        MPSiteKey siteKey = mpw_siteKey(
 | 
			
		||||
                masterKey, (char *)siteName, siteCounter, siteVariant, (char *)siteContext, algorithm );
 | 
			
		||||
                masterKey, (char *)siteName, siteCounter, siteVariant, (char *)keyContext, algorithm );
 | 
			
		||||
        const char *sitePassword = mpw_sitePassword(
 | 
			
		||||
                siteKey, siteType, algorithm );
 | 
			
		||||
        mpw_free( masterKey, MPMasterKeySize );
 | 
			
		||||
@@ -77,9 +75,9 @@ int main(int argc, char *const argv[]) {
 | 
			
		||||
        xmlFree( masterPassword );
 | 
			
		||||
        xmlFree( keyID );
 | 
			
		||||
        xmlFree( siteName );
 | 
			
		||||
        xmlFree( siteTypeString );
 | 
			
		||||
        xmlFree( siteVariantString );
 | 
			
		||||
        xmlFree( siteContext );
 | 
			
		||||
        xmlFree( passwordTypeString );
 | 
			
		||||
        xmlFree( keyPurposeString );
 | 
			
		||||
        xmlFree( keyContext );
 | 
			
		||||
        xmlFree( result );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user