C4Err RNG_GetPassPhrase( size_t bits, char ** outPassPhrase ) { C4Err err = kC4Err_NoErr; size_t passBytesLen = bits/8; uint8_t* passBytes = XMALLOC(passBytesLen); size_t passPhraseLen = (passBytesLen *2) +1; uint8_t* passPhrase = XMALLOC(passPhraseLen); err = RNG_GetBytes(passBytes,passBytesLen); CKERR; bin2hex(passBytes, passBytesLen, passPhrase, &passPhraseLen); passPhrase[passPhraseLen] = '\0' ; if(outPassPhrase) *outPassPhrase = (char*) passPhrase; done: ZERO(passBytes, passBytesLen); XFREE(passBytes); return err; }
S4Err TestSecretSharing() { S4Err err = kS4Err_NoErr; uint8_t PT[PTsize]; uint8_t PT1[sizeof (PT)]; size_t keyLen = 0; SHARES_ShareInfo* shareInfo[kNumShares]; SHARES_ShareInfo* testShares[kShareThreshold]; uint8_t testOffset[kShareThreshold]; SHARES_ContextRef shareCTX = kInvalidSHARES_ContextRef; uint32_t i; OPTESTLogInfo("\nTesting Shamir Key Spliting\n"); // create a random key err = RNG_GetBytes(PT, sizeof(PT)); CKERR; OPTESTLogVerbose("\t\tKey Data: (%ld bytes)\n", PTsize); dumpHex(IF_LOG_DEBUG, PT, (int)sizeof (PT), 0); OPTESTLogDebug("\n"); err = SHARES_Init( PT, sizeof(PT), kNumShares, kShareThreshold, &shareCTX); CKERR; for(i = 0; i < kNumShares; i++) { size_t shareLen = 0; err = SHARES_GetShareInfo(shareCTX, i, &shareInfo[i], &shareLen); CKERR; if(IF_LOG_VERBOSE) { OPTESTLogVerbose("\t Share %d: (%d bytes)\n", i,shareLen); dumpHex(IF_LOG_DEBUG, shareInfo[i]->shareSecret , (int)shareInfo[i]->shareSecretLen, 0); OPTESTLogVerbose("\n"); } // OPTESTLogVerbose("\t Check shares for data leakage against known original message..."); // /* check shares for data leakage against known original message */ // err = CMP(shareBuf+(shareSize *i) + kSHAMIR_HEADERSIZE, // PT, sizeof (PT)) // ? kS4Err_SelfTestFailed : kS4Err_NoErr; // CKERR; } // create threshold number of shares to test with sCreateTestOffsets(testOffset, sizeof(testOffset)); for(i = 0; i < kShareThreshold; i++) testShares[i] = shareInfo[testOffset[i]]; /* attempt to combine with not enough shares */ err = SHARES_CombineShareInfo(kShareThreshold -1, testShares, PT1, sizeof(PT1), &keyLen); OPTESTLogVerbose("\t Attempt to combine with not enough shares = %s\n", IsS4Err(err)?"fail":"pass"); if(err == kS4Err_NotEnoughShares) err = kS4Err_NoErr; CKERR; /* Reconstruct data */ OPTESTLogVerbose("\t Reconstructing data with just %d shares...",kShareThreshold); err = SHARES_CombineShareInfo(kShareThreshold, testShares, PT1, sizeof(PT1), &keyLen); CKERR; OPTESTLogVerbose("OK\n"); /* check result against known original message */ OPTESTLogVerbose("\t Check result against known original message...\n"); err = compare2Results(PT, sizeof(PT), PT1, keyLen, kResultFormat_Byte, "SHAMIR Reconstruct"); //CKERR; OPTESTLogInfo("\n"); done: for(i = 0; i < kNumShares; i++) { if(shareInfo[i]) XFREE(shareInfo[i]); } if(SHARES_ContextRefIsValid(shareCTX)) SHARES_Free(shareCTX); return err; }
static SCLError scSaveRestoreKeyTest(SCKeySuite storageKeySuite, SCKeySuite eccKeySuite ) { SCLError err = kSCLError_NoErr; SCKeyContextRef sKey = kInvalidSCKeyContextRef; // storage key SCKeyContextRef signKey = kInvalidSCKeyContextRef; SCKeyContextRef pKey = kInvalidSCKeyContextRef; // pbdkf2 encrypted storage key Cipher_Algorithm algorithm = kCipher_Algorithm_Invalid; size_t symKeyLen = 0; time_t startDate = time(NULL) ; time_t expireDate = startDate + (3600 * 24); char* user1 = "*****@*****.**"; uint8_t* keyData = NULL; size_t keyDataLen = 0; uint8_t* sKeyData = NULL; size_t sKeyDataLen = 0; bool isLocked = true; char* passPhrase = "Pedicabo ego vos et irrumabo"; // used for comparison test ECC_ContextRef ecc = kInvalidECC_ContextRef; ECC_ContextRef ecc1 = kInvalidECC_ContextRef; OPTESTLogInfo("\tTesting SCKeys %s Save/Restore using %s\n", sckey_suite_table(eccKeySuite), sckey_suite_table(storageKeySuite)); // setup a storage key for the private SCC key */ // we do this code just one time and export the encrypted passphrase for later use. char* nonce = "some stupid nonce data"; uint8_t IV[32]; err = SCKeyCipherForKeySuite(storageKeySuite, &algorithm, &symKeyLen); CKERR; err = RNG_GetBytes(IV,symKeyLen); CKERR; err = SCKeyNew(storageKeySuite, (uint8_t*)nonce, strlen(nonce), &sKey); CKERR; err = SCKeySetProperty (sKey, kSCKeyProp_IV, SCKeyPropertyType_Binary, IV , symKeyLen ); CKERR; err = SCKeyEncryptToPassPhrase(sKey, (const uint8_t*)passPhrase, strlen(passPhrase), &pKey); CKERR; err = SCKeySerialize(pKey, &sKeyData, &sKeyDataLen); CKERR; OPTESTLogVerbose("\t\tExport storage key (%d bytes)\n", (int)sKeyDataLen ); OPTESTLogDebug("\t\tEncrypted Storage Key Packet: (%ld bytes)\n%s\n",sKeyDataLen, (char*)sKeyData); SCKeyFree(pKey); pKey = NULL; /* create a signing key for things like voicemail, etc */ err = SCKeyNew(eccKeySuite, (uint8_t*)nonce, strlen(nonce), &signKey); CKERR; err = SCKeySetProperty (signKey, kSCKeyProp_Owner, SCKeyPropertyType_UTF8String, user1 , strlen(user1) ); CKERR; err = SCKeySetProperty(signKey, kSCKeyProp_StartDate, SCKeyPropertyType_Time , &startDate, sizeof(time_t)); CKERR; err = SCKeySetProperty(signKey, kSCKeyProp_ExpireDate, SCKeyPropertyType_Time , &expireDate, sizeof(time_t)); CKERR; // used for testing err = SCKeyExport_ECC(signKey, &ecc); CKERR; /* save the private ecc key */ err = SCKeySerializePrivateWithSCKey(signKey, sKey, &keyData, &keyDataLen); CKERR; OPTESTLogVerbose("\t\tExport ECC key (%d bytes)\n", (int)keyDataLen ); OPTESTLogDebug("\t\tPrivate Key Packet: (%ld bytes)\n%s\n",keyDataLen, (char*)keyData); SCKeyFree(sKey); sKey = NULL; SCKeyFree(signKey); signKey = NULL; // pretend we readin keyData and sKeyData from some device.. OPTESTLogVerbose("\t\tReconstitute the storage key \n" ); // reconstitute the storage key err = SCKeyDeserialize(sKeyData, strlen((char*) sKeyData) , &pKey); CKERR; err = SCKeyDecryptFromPassPhrase(pKey, (const uint8_t*)passPhrase, strlen(passPhrase), &sKey); CKERR; // resconstitute the ECC key OPTESTLogVerbose("\t\tReconstitute the ECC key \n" ); err = SCKeyDeserialize(keyData, strlen((char*) keyData) , &signKey); CKERR; OPTESTLogVerbose("\t\tUnlock Private Key Packet \n" ); err = SCKeyUnlockWithSCKey(signKey, sKey); CKERR; err = SCKeyIsLocked(signKey,&isLocked); CKERR; ASSERTERR(isLocked, kSCLError_SelfTestFailed); OPTESTLogVerbose("\t\tConsistency check of reimported key \n" ); { uint8_t pk[128]; size_t pkLen = sizeof (pk); uint8_t pk1[128]; size_t pk1Len = sizeof (pk1); uint8_t privKey[256]; size_t privKeyLen = sizeof (privKey); uint8_t privKey1[256]; size_t privKey1Len = sizeof (privKey1); err = SCKeyExport_ECC(signKey, &ecc1); CKERR; err = ECC_Export_ANSI_X963(ecc , pk, pkLen, &pkLen); err = ECC_Export_ANSI_X963(ecc1 , pk1, pk1Len, &pk1Len); err = compare2Results(pk, pkLen, pk1, pk1Len, kResultFormat_Byte, "ECC public Key"); err = ECC_Export(ecc, true, privKey, sizeof(privKey), &privKeyLen);CKERR; err = ECC_Export(ecc1, true, privKey1, sizeof(privKey1), &privKey1Len);CKERR; err = compare2Results(privKey, privKeyLen, privKey1, privKey1Len, kResultFormat_Byte, "ECC private Key"); } done: OPTESTLogDebug("\n" ); if(ECC_ContextRefIsValid(ecc)) ECC_Free(ecc); if(ECC_ContextRefIsValid(ecc1)) ECC_Free(ecc1); if(SCKeyContextRefIsValid(pKey)) SCKeyFree(pKey); if(SCKeyContextRefIsValid(pKey)) SCKeyFree(pKey); if(SCKeyContextRefIsValid(signKey)) SCKeyFree(signKey); if(SCKeyContextRefIsValid(sKey)) SCKeyFree(sKey); return err; }
static SCLError sSCKeysStorageTest(SCKeySuite keySuite) { SCLError err = kSCLError_NoErr; SCKeyContextRef storageKey = kInvalidSCKeyContextRef; SCKeyContextRef pKey = kInvalidSCKeyContextRef; const char* passphrase = "Tant las fotei com auziretz"; uint8_t* keyData = NULL; size_t keyDataLen = 0; Cipher_Algorithm algorithm = kCipher_Algorithm_Invalid; size_t symKeyLen = 0; int msg_count = ( sizeof(Msgs) / sizeof(char*)) -1; typedef struct { uint8_t *data; size_t len; }storage_entry; storage_entry *msg_store = NULL; uint8_t deviceUUID[32]; uint8_t IV[32]; OPTESTLogInfo("\tTesting SCKeys Storage API (%s)\n", sckey_suite_table(keySuite)); msg_store = XMALLOC(sizeof(storage_entry) * msg_count); CKNULL(msg_store); ZERO(msg_store,sizeof(storage_entry) * msg_count); // we use the UUID only as a nonce, it should be unique but doesnt have to be secure err = RNG_GetBytes(deviceUUID,sizeof(deviceUUID)); // generate a 128 bit storagre key and a 128 bit IV err = RNG_GetBytes(IV,sizeof(IV)); err = SCKeyCipherForKeySuite(keySuite, &algorithm, &symKeyLen); CKERR; OPTESTLogVerbose("\t\tCreate %s encyption key\n",cipher_algor_table(algorithm)); err = SCKeyNew(keySuite, deviceUUID, sizeof(deviceUUID), &storageKey); CKERR; err = SCKeySetProperty (storageKey, kSCKeyProp_IV, SCKeyPropertyType_Binary, IV , symKeyLen); CKERR; OPTESTLogVerbose("\t\tEncrypt %d test messages\n", msg_count); // Encrypt a bunch of messages for(int i = 0; Msgs[i] != NULL; i++) { unsigned long msgLen; msgLen = strlen(Msgs[i]); OPTESTLogDebug("\t\t %3d - %3d bytes |%.*s|\n", i+1, (int)msgLen,(int)msgLen, Msgs[i] ); err = SCKeyStorageEncrypt(storageKey, (uint8_t*) Msgs[i], msgLen, &msg_store[i].data, &msg_store[i].len); CKERR; dumpHex(IF_LOG_DEBUG, msg_store[i].data, (int)msg_store[i].len, 0); OPTESTLogDebug("\n"); } OPTESTLogVerbose("\t\tSecure the storage key to a passphrase\n"); // secure the storage key to a passphrase err = SCKeyEncryptToPassPhrase(storageKey, (uint8_t*)passphrase, strlen(passphrase), &pKey); CKERR; // get rid of orignial storage key SCKeyFree(storageKey); storageKey = NULL; err = SCKeySerialize(pKey, &keyData, &keyDataLen); CKERR; SCKeyFree(pKey); pKey = NULL; ZERO(IV,sizeof(IV)); // save the passphrase key somewhere OPTESTLogDebug("\t\tPBKDF2 Passphrase Key Packet: (%ld bytes)\n%s\n",keyDataLen, (char*)keyData); // restore the passphrase key err = SCKeyDeserialize(keyData, keyDataLen, &pKey);CKERR; // unlock passphrase key and make a SKey err = SCKeyDecryptFromPassPhrase(pKey, (uint8_t*)passphrase, strlen(passphrase), &storageKey ); CKERR; SCKeyFree(pKey); pKey = NULL; OPTESTLogVerbose("\t\tDecrypt and compare %d messages\n", msg_count); for(int i = 0; Msgs[i] != NULL; i++) { unsigned long msgLen; uint8_t* PT = NULL; size_t PTLen = 0; msgLen = strlen(Msgs[i]); err = SCKeyStorageDecrypt(storageKey, msg_store[i].data, msg_store[i].len, &PT, &PTLen); CKERR; if(msgLen != PTLen) { OPTESTLogInfo("ERROR MSG Decrypt: Expecting %d bytes, got %d\n", (int)msgLen, (int)PTLen ); RETERR(kSCLError_SelfTestFailed); } err = compareResults( Msgs[i], PT, msgLen , kResultFormat_Byte, "MSG Decrypt"); CKERR; if(PT) XFREE(PT); PT = NULL; } SCKeyFree(storageKey); storageKey = NULL; OPTESTLogVerbose("\n"); done: for(int i = 0; i < msg_count; i++) { if(msg_store[i].data ) { XFREE(msg_store[i].data); } } XFREE(msg_store); if(SCKeyContextRefIsValid(pKey)) SCKeyFree(pKey); if(SCKeyContextRefIsValid(storageKey)) SCKeyFree(storageKey); return err; }
C4Err PASS_TO_KEY_SETUP( unsigned long password_len, unsigned long key_len, uint8_t *salt, unsigned long salt_len, uint32_t *rounds_out) { C4Err err = kC4Err_NoErr; uint8_t *password = NULL; uint8_t *key = NULL; uint32_t rounds = MIN_ROUNDS; #if _USES_COMMON_CRYPTO_ rounds = CCCalibratePBKDF(kCCPBKDF2,password_len, salt_len, kCCPRFHmacAlgSHA256, key_len, 100 ); rounds = rounds > MIN_ROUNDS?rounds:MIN_ROUNDS; *rounds_out = rounds; #else uint64_t startTime, endTime, elapsedTime; uint64_t msec = 100; // 0.1s ? int i; // random password and salt password = XMALLOC(password_len); CKNULL(password); key = XMALLOC(key_len); CKNULL(key); err = RNG_GetBytes( password, password_len ); CKERR; err = RNG_GetBytes( salt, salt_len ); CKERR; // run and calculate elapsed time. for(elapsedTime = 0, i=0; i < 10 && elapsedTime == 0; i++) { startTime = clock(); err = PASS_TO_KEY (password, password_len, salt, salt_len, ROUNDMEASURE, key, key_len); CKERR; endTime = clock(); elapsedTime = endTime - startTime; } if(elapsedTime == 0) RETERR(kC4Err_UnknownError); // How many rounds to use so that it takes 0.1s ? rounds = (uint32_t) ((uint64_t)(msec * ROUNDMEASURE * 1000) / elapsedTime); rounds = rounds > MIN_ROUNDS?rounds:MIN_ROUNDS; *rounds_out = rounds; #endif done: if(password) XFREE(password); if(key) XFREE(key); return err; } // PASS_TO_KEY_SETUP()