/** * scryptenc_cpuperf(opps): * Estimate the number of salsa20/8 cores which can be executed per second, * and return the value via opps. */ int scryptenc_cpuperf(double * opps) { struct timespec st; double resd, diffd; uint64_t i = 0; /* Get the clock resolution. */ if (getclockres(&resd)) return (2); #ifdef DEBUG fprintf(stderr, "Clock resolution is %f\n", resd); #endif /* Loop until the clock ticks. */ if (getclocktime(&st)) return (2); do { /* Do an scrypt. */ if (crypto_scrypt(NULL, 0, NULL, 0, 16, 1, 1, NULL, 0)) return (3); /* Has the clock ticked? */ if (getclockdiff(&st, &diffd)) return (2); if (diffd > 0) break; } while (1); /* Could how many scryps we can do before the next tick. */ if (getclocktime(&st)) return (2); do { /* Do an scrypt. */ if (crypto_scrypt(NULL, 0, NULL, 0, 128, 1, 1, NULL, 0)) return (3); /* We invoked the salsa20/8 core 512 times. */ i += 512; /* Check if we have looped for long enough. */ if (getclockdiff(&st, &diffd)) return (2); if (diffd > resd) break; } while (1); #ifdef DEBUG fprintf(stderr, "%u salsa20/8 cores performed in %f seconds\n", (uintmax_t)i, diffd); #endif /* We can do approximately i salsa20/8 cores per diffd seconds. */ *opps = i / diffd; return (0); }
bool derive_kek(uint8_t *passwd, size_t len, kdfp *kdfp, uint8_t *kek, size_t klen) { uint8_t *salt = kdfp->salt; uint64_t N = kdfp->N; uint64_t r = kdfp->r; uint64_t p = kdfp->p; return crypto_scrypt(passwd, len, salt, SALT_LEN, N, r, p, kek, klen) == 0; }
lj::Uuid Auth_method_password_hash::authenticate(const lj::bson::Node& data) const { const std::string login(lj::bson::as_string(data[k_login_field])); auto iter = credentials_by_login_.find(login); if (iter == credentials_by_login_.end()) { // Deal with unknown login. lj::log::format<lj::Debug>("auth_local: User not found for %s.") << login << lj::log::end; throw logjam::User_not_found_exception(login); } const lj::bson::Node* stored_credential = (*iter).second; // Prepare scrypt inputs lj::log::format<lj::Debug>("auth_local: Calculating derived key."); const size_t password_length = data[k_password_field].size(); const uint8_t* password = data[k_password_field].to_value(); const size_t salt_length = stored_credential->nav(k_salt_field).size(); const uint8_t* salt = stored_credential->nav(k_salt_field).to_value(); // calculate the derived key. uint8_t derived_key[k_derived_key_length]; crypto_scrypt(password, password_length, salt, salt_length, k_N, k_r, k_p, derived_key, k_derived_key_length); // Get the stored derived key. lj::bson::Binary_type bin_type = lj::bson::Binary_type::k_bin_generic; uint32_t check_key_length = 0; const uint8_t* check_key = lj::bson::as_binary(stored_credential->nav(k_password_field), &bin_type, &check_key_length); // Compare the two keys. Abort if they don't match. for (size_t h = 0; h < k_derived_key_length; ++h) { if (derived_key[h] != check_key[h]) { lj::log::format<lj::Debug>( "auth_local: Credentials did not match for %s.") << login << lj::log::end; throw logjam::User_not_found_exception(login); } } // Login successful, return the user object. lj::log::format<lj::Debug>("auth_local: Authenticated user %s.") << login << lj::log::end; return lj::bson::as_uuid(stored_credential->nav(k_id_field)); }
data_chunk scrypt(data_slice data, data_slice salt, uint64_t N, uint32_t p, uint32_t r, size_t length) { data_chunk output(length); const auto result = crypto_scrypt(data.data(), data.size(), salt.data(), salt.size(), N, r, p, output.data(), output.size()); handle_script_result(result); return output; }
int main(int argc, char *argv[]) { Cmd * c = NULL; void * buf = NULL; uint32_t buffer_limit = 131072; /* 128k */ #ifdef _WIN32 _setmode( _fileno( stdout ), _O_BINARY ); _setmode( _fileno( stdin ), _O_BINARY ); #endif if (argc > 1) { buffer_limit = atol(argv[1]); } while (1) { c = read_cmd(); if (c == NULL) { fprintf(stderr, "command read failed\n"); exit(1); } if ((c->hdr.passwdlen > buffer_limit) || (c->hdr.saltlen > buffer_limit) || (c->hdr.buflen > buffer_limit)) { fprintf(stderr, "buffer limit exceeded\n"); exit(1); } buf = calloc(1, c->hdr.buflen); if (buf == NULL) { fprintf(stderr, "buffer allocation for buf failed\n"); exit(1); } if (crypto_scrypt((const uint8_t*)c->passwd, c->hdr.passwdlen, (const uint8_t*)c->salt, c->hdr.saltlen, c->hdr.N, c->hdr.r, c->hdr.p, (uint8_t*)buf, c->hdr.buflen)) { fprintf(stderr, "crypto_scrypt failed\n"); exit(1); } write_uint32(c->hdr.buflen); if (fwrite(buf, c->hdr.buflen, 1, stdout) != 1) { perror("fwrite buf"); exit(1); } fflush(stdout); free(c); free(buf); c = NULL; buf = NULL; } }
void SCrypt::derive(void *destination, size_t size, const string &password) { _checkCallOnlyOnce(); int errorcode = crypto_scrypt(reinterpret_cast<const uint8_t*>(password.c_str()), password.size(), reinterpret_cast<const uint8_t*>(_config.salt().data()), _config.salt().size(), _config.N(), _config.r(), _config.p(), static_cast<uint8_t*>(destination), size); if (errorcode != 0) { throw std::runtime_error("Error running scrypt key derivation."); } }
// // This is the actual key derivation function. // It is binary safe and is exposed to this module for // access to the underlying key derivation function of Scrypt // unsigned int ScryptHashFunction(const uint8_t* key, size_t keylen, const uint8_t *salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p,uint8_t *buf, size_t buflen) { int rc = crypto_scrypt(key, keylen, salt, saltlen, N, r, p, buf, buflen); unsigned int error = (rc == 0) ? 0 : 3; if (error && errno) { error |= (errno << 16); } return (error); }
static int scryptenc_setup(uint8_t header[96], uint8_t dk[64], const uint8_t * passwd, size_t passwdlen, size_t maxmem, double maxmemfrac, double maxtime) { uint8_t salt[32]; uint8_t hbuf[32]; int logN; uint64_t N; uint32_t r; uint32_t p; SHA256_CTX ctx; uint8_t * key_hmac = &dk[32]; HMAC_SHA256_CTX hctx; int rc; /* Pick values for N, r, p. */ if ((rc = pickparams(maxmem, maxmemfrac, maxtime, &logN, &r, &p)) != 0) return (rc); N = (uint64_t)(1) << logN; /* Get some salt. */ if (crypto_entropy_read(salt, 32)) return (4); /* Generate the derived keys. */ if (crypto_scrypt(passwd, passwdlen, salt, 32, N, r, p, dk, 64)) return (3); /* Construct the file header. */ memcpy(header, "scrypt", 6); header[6] = 0; header[7] = logN; be32enc(&header[8], r); be32enc(&header[12], p); memcpy(&header[16], salt, 32); /* Add header checksum. */ SHA256_Init(&ctx); SHA256_Update(&ctx, header, 48); SHA256_Final(hbuf, &ctx); memcpy(&header[48], hbuf, 16); /* Add header signature (used for verifying password). */ HMAC_SHA256_Init(&hctx, key_hmac, 32); HMAC_SHA256_Update(&hctx, header, 64); HMAC_SHA256_Final(hbuf, &hctx); memcpy(&header[64], hbuf, 32); /* Success! */ return (0); }
static int scryptdec_setup(const uint8_t header[96], uint8_t dk[64], const uint8_t * passwd, size_t passwdlen, size_t maxmem, double maxmemfrac, double maxtime, int verbose) { uint8_t salt[32]; uint8_t hbuf[32]; int logN; uint32_t r; uint32_t p; uint64_t N; SHA256_CTX ctx; uint8_t * key_hmac = &dk[32]; HMAC_SHA256_CTX hctx; int rc; /* Parse N, r, p, salt. */ logN = header[7]; r = be32dec(&header[8]); p = be32dec(&header[12]); memcpy(salt, &header[16], 32); /* Verify header checksum. */ SHA256_Init(&ctx); SHA256_Update(&ctx, header, 48); SHA256_Final(hbuf, &ctx); if (memcmp(&header[48], hbuf, 16)) return (7); /* * Check whether the provided parameters are valid and whether the * key derivation function can be computed within the allowed memory * and CPU time. */ if ((rc = checkparams(maxmem, maxmemfrac, maxtime, logN, r, p, verbose)) != 0) return (rc); /* Compute the derived keys. */ N = (uint64_t)(1) << logN; if (crypto_scrypt(passwd, passwdlen, salt, 32, N, r, p, dk, 64)) return (3); /* Check header signature (i.e., verify password). */ HMAC_SHA256_Init(&hctx, key_hmac, 32); HMAC_SHA256_Update(&hctx, header, 64); HMAC_SHA256_Final(hbuf, &hctx); if (memcmp(hbuf, &header[64], 32)) return (11); /* Success! */ return (0); }
Status ScryptSnrp::hash(DataChunk &result, DataSlice data, size_t size) const { DataChunk out(size); int rc = crypto_scrypt(data.data(), data.size(), salt.data(), salt.size(), n, r, p, out.data(), size); if (rc) return ABC_ERROR(ABC_CC_ScryptError, "Error calculating Scrypt hash"); result = std::move(out); return Status(); }
uint8_t const *mpw_scrypt(const size_t keySize, const char *secret, const uint8_t *salt, const size_t saltSize, uint64_t N, uint32_t r, uint32_t p) { uint8_t *key = malloc( keySize ); if (!key) return NULL; if (crypto_scrypt( (const uint8_t *)secret, strlen( secret ), salt, saltSize, N, r, p, key, keySize ) < 0) { mpw_free( key, keySize ); return NULL; } return key; }
jbyteArray JNICALL scryptN(JNIEnv *env, jclass cls, jbyteArray passwd, jbyteArray salt, jint N, jint r, jint p, jint dkLen) { #ifdef ANDROID log_basic_info(); log_params(env, passwd, salt, N, r, p, dkLen); #endif jint Plen = (*env)->GetArrayLength(env, passwd); jint Slen = (*env)->GetArrayLength(env, salt); jbyte *P = (*env)->GetByteArrayElements(env, passwd, NULL); jbyte *S = (*env)->GetByteArrayElements(env, salt, NULL); uint8_t *buf = malloc(sizeof(uint8_t) * dkLen); jbyteArray DK = NULL; if (P == NULL || S == NULL || buf == NULL) goto cleanup; if (crypto_scrypt((uint8_t *) P, Plen, (uint8_t *) S, Slen, N, r, p, buf, dkLen)) { jclass e = (*env)->FindClass(env, "java/lang/IllegalArgumentException"); char *msg; switch (errno) { case EINVAL: msg = "N must be a power of 2 greater than 1"; break; case EFBIG: case ENOMEM: msg = "Insufficient memory available"; break; default: msg = "Memory allocation failed"; } (*env)->ThrowNew(env, e, msg); goto cleanup; } DK = (*env)->NewByteArray(env, dkLen); if (DK == NULL) goto cleanup; (*env)->SetByteArrayRegion(env, DK, 0, dkLen, (jbyte *) buf); cleanup: if (P) (*env)->ReleaseByteArrayElements(env, passwd, P, JNI_ABORT); if (S) (*env)->ReleaseByteArrayElements(env, salt, S, JNI_ABORT); if (buf) free(buf); return DK; }
static int crypt_all(int *pcount, struct db_salt *salt) { int count = *pcount; int index = 0; #ifdef _OPENMP #pragma omp parallel for for (index = 0; index < count; index++) #endif { crypto_scrypt((unsigned char*)saved_key[index], strlen((char*)saved_key[index]), cur_salt->salt, strlen((char*)cur_salt->salt), (1ULL) << cur_salt->N, cur_salt->r, cur_salt->p, (unsigned char*)crypt_out[index], BINARY_SIZE); } return count; }
std::vector<unsigned char> decrypt_bip38_ec(const std::vector<unsigned char> key, const std::string& passwd) { int i; uint8_t passfactor[PASSFACTOR_SIZE]; memset(passfactor,0,PASSFACTOR_SIZE); const unsigned char * s_key = reinterpret_cast<const unsigned char*>(key.data()); crypto_scrypt((const uint8_t *)passwd.c_str(), passwd.length(), &s_key[3 + ADDRESSHASH_SIZE], OWNERSALT_SIZE, 16384, 8, 8, passfactor, PASSFACTOR_SIZE ); // compute EC point (passpoint) using passfactor struct bp_key ec_point; if(!bp_key_init(&ec_point)) { fprintf(stderr,"%s","cannot init EC point key"); exit(3); } if(!bp_key_secret_set(&ec_point,passfactor,PASSFACTOR_SIZE)) { fprintf(stderr,"%s","cannot set EC point from passfactor"); exit(3); } // get the passpoint as bytes unsigned char * passpoint; size_t passpoint_len; if(!bp_pubkey_get(&ec_point,(unsigned char **)&passpoint,&passpoint_len)) { fprintf(stderr,"%s","cannot get pubkey for EC point"); exit(4); } // now we need to decrypt seedb uint8_t encryptedpart2[16]; memset(encryptedpart2,0,16); memcpy(encryptedpart2, &s_key[3 + ADDRESSHASH_SIZE + OWNERSALT_SIZE + 8], 16); uint8_t encryptedpart1[16]; memset(encryptedpart1,0,16); memcpy(encryptedpart1, &s_key[3 + ADDRESSHASH_SIZE + OWNERSALT_SIZE], 8); unsigned char derived[DERIVED_SIZE]; // get the encryption key for seedb using scrypt // with passpoint as the key, salt is addresshash+ownersalt unsigned char derived_scrypt_salt[ADDRESSHASH_SIZE + OWNERSALT_SIZE]; memcpy(derived_scrypt_salt, &s_key[3], ADDRESSHASH_SIZE); // copy the addresshash memcpy(derived_scrypt_salt+ADDRESSHASH_SIZE, &s_key[3+ADDRESSHASH_SIZE], OWNERSALT_SIZE); // copy the ownersalt crypto_scrypt( passpoint, passpoint_len, derived_scrypt_salt, ADDRESSHASH_SIZE+OWNERSALT_SIZE, 1024, 1, 1, derived, DERIVED_SIZE ); //get decryption key unsigned char derivedhalf2[DERIVED_SIZE/2]; memcpy(derivedhalf2, derived+(DERIVED_SIZE/2), DERIVED_SIZE/2); unsigned char iv[32]; memset(iv,0,32); EVP_CIPHER_CTX d; EVP_CIPHER_CTX_init(&d); EVP_DecryptInit_ex(&d, EVP_aes_256_ecb(), NULL, derivedhalf2, iv); unsigned char unencryptedpart2[32]; int decrypt_len; EVP_DecryptUpdate(&d, unencryptedpart2, &decrypt_len, encryptedpart2, 16); EVP_DecryptUpdate(&d, unencryptedpart2, &decrypt_len, encryptedpart2, 16); for(i=0; i<16; i++) { unencryptedpart2[i] ^= derived[i + 16]; } unsigned char unencryptedpart1[32]; memcpy(encryptedpart1+8, unencryptedpart2, 8); EVP_DecryptUpdate(&d, unencryptedpart1, &decrypt_len, encryptedpart1, 16); EVP_DecryptUpdate(&d, unencryptedpart1, &decrypt_len, encryptedpart1, 16); for(i=0; i<16; i++) { unencryptedpart1[i] ^= derived[i]; } // recoved seedb unsigned char seedb[24]; memcpy(seedb, unencryptedpart1, 16); memcpy(&(seedb[16]), &(unencryptedpart2[8]), 8); // turn seedb into factorb (factorb = SHA256(SHA256(seedb))) unsigned char factorb[32]; bu_Hash(factorb, seedb, 24); // multiply by passfactor (ec_point_pub) const EC_GROUP * ec_group = EC_KEY_get0_group(ec_point.k); const EC_POINT * ec_point_pub = EC_KEY_get0_public_key(ec_point.k); BIGNUM * bn_passfactor = BN_bin2bn(passfactor,32,BN_new()); BIGNUM * bn_factorb = BN_bin2bn(factorb,32,BN_new()); BIGNUM * bn_res = BN_new(); BIGNUM * bn_final = BN_new(); BIGNUM * bn_n = BN_new(); BN_CTX * ctx = BN_CTX_new(); EC_GROUP_get_order(ec_group, bn_n, ctx); BN_mul(bn_res, bn_passfactor, bn_factorb, ctx); BN_mod(bn_final, bn_res, bn_n, ctx); unsigned char finalKey[32]; memset(finalKey, 0, 32); int n = BN_bn2bin(bn_final, finalKey); BN_clear_free(bn_passfactor); BN_clear_free(bn_factorb); BN_clear_free(bn_res); BN_clear_free(bn_n); BN_clear_free(bn_final); printf("\n"); print_hex((char *)finalKey, 32); printf("\n"); std::vector<unsigned char> out; out.assign(finalKey, finalKey + 32); return out; }
int salsa20_init(salsa20_ctx_t *ctx, uchar_t *salt, int saltlen, uchar_t *pwd, int pwd_len, uchar_t *nonce, int enc) { struct timespec tp; uint64_t tv; uchar_t num[25]; uchar_t IV[32]; uchar_t *key = ctx->pkey; #ifndef _USE_PBK int logN; uint32_t r, p; uint64_t N; if (XSALSA20_CRYPTO_NONCEBYTES % 8) { log_msg(LOG_ERR, 0, "XSALSA20_CRYPTO_NONCEBYTES is not a multiple of 8!\n"); return (-1); } pickparams(&logN, &r, &p); N = (uint64_t)(1) << logN; if (crypto_scrypt(pwd, pwd_len, salt, saltlen, N, r, p, key, ctx->keylen)) { log_msg(LOG_ERR, 0, "Scrypt failed\n"); return (-1); } #else rv = PKCS5_PBKDF2_HMAC(pwd, pwd_len, salt, saltlen, PBE_ROUNDS, EVP_sha256(), ctx->keylen, key); if (rv != ctx->keylen) { log_msg(LOG_ERR, 0, "Key size is %d bytes - should be %d bits\n", i, ctx->keylen); return (-1); } #endif /* * Copy the key. XSalsa20 core cipher always uses a 256-bit key. If we are using a * 128-bit key then the key value is repeated twice to form a 256-bit value. * This approach is based on the Salsa20 code submitted to eSTREAM. See the function * ECRYPT_keysetup() in the Salsa20 submission: * http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/ref/salsa20.c?rev=161&view=auto * * The input values corresponding to a 256-bit key contain repeated values if key * length is 128-bit. */ memcpy(ctx->key, key, ctx->keylen); if (ctx->keylen < XSALSA20_CRYPTO_KEYBYTES) { uchar_t *k; k = ctx->key + ctx->keylen; memcpy(k, key, XSALSA20_CRYPTO_KEYBYTES - ctx->keylen); } if (enc) { int i; uint64_t *n, *n1; // Derive 192-bit nonce if (RAND_status() != 1 || RAND_bytes(IV, XSALSA20_CRYPTO_NONCEBYTES) != 1) { if (geturandom_bytes(IV, XSALSA20_CRYPTO_NONCEBYTES) != 0) { if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1) { time((time_t *)&tv); } else { tv = tp.tv_sec * 1000UL + tp.tv_nsec; } sprintf((char *)num, "%" PRIu64, tv); PKCS5_PBKDF2_HMAC((const char *)num, strlen((char *)num), salt, saltlen, PBE_ROUNDS, EVP_sha256(), 32, IV); } } n = (uint64_t *)IV; n1 = (uint64_t *)(ctx->nonce); for (i = 0; i < XSALSA20_CRYPTO_NONCEBYTES/8; i++) { *n1 = LE64(*n); n++; n1++; } // Nullify stack components memset(num, 0, 25); memset(IV, 0, 32); memset(&tp, 0, sizeof (tp)); tv = 0; } else { memcpy(ctx->nonce, nonce, XSALSA20_CRYPTO_NONCEBYTES); memset(nonce, 0, XSALSA20_CRYPTO_NONCEBYTES); } return (0); }
int main(int argc, char* argv[]) { char * passwd; uint64_t N = 1 << 14; uint32_t r = 8; uint32_t p = 1; char buf[65]; size_t buflen = 64; int result; int i = 0; int punctuation = 1; // Whether to allow punctuation in the output int addbang = 0; // The the first character '!' int addfive = 0; // Make the 5th character '5' int length = 10; // Desired password length if (argc < 2) { usage(); } // Disable punctuation in output for sites that are jerks if (strcmp(argv[1], "chase.com") == 0 || strcmp(argv[1], "fandango.com") == 0 || //strcmp(argv[1], "apple.com") == 0 || strcmp(argv[1], "comcast.com") == 0 || strcmp(argv[1], "verizonwireless.com") == 0 || strcmp(argv[1], "gap.com") == 0 || strcmp(argv[1], "audible.com") == 0 || strcmp(argv[1], "purpletie.com") == 0 || strcmp(argv[1], "opentable.com") == 0 || strcmp(argv[1], "videoeta.com") == 0 || strcmp(argv[1], "topcoder.com") == 0 || strcmp(argv[1], "hondafinancialservices.com") == 0 || strcmp(argv[1], "americanexpress.com") == 0 || argc == 3) { punctuation = 0; } else if (strcmp(argv[1], "kaiserpermanente.org") == 0) { addbang = 1; } else if (strcmp(argv[1], "schwab.com") == 0) { // Schwab may have the stupidest password requirements I've ever // encountered. length = 8; addfive = 1; punctuation = 0; } else if (strcmp(argv[1], "deltadentalins.com") == 0 || strcmp(argv[1], "mozilla.org") == 0 || strcmp(argv[1], "morganstanleysmithbarney.com") == 0) { addfive = 1; } /* Prompt for a password. */ if (tarsnap_readpass(&passwd, "Please enter passphrase", NULL, 1)) { exit(1); } result = crypto_scrypt(passwd, strlen(passwd), argv[1], strlen(argv[1]), N, r, p, buf, buflen); buf[64] = 0; if (result != 0) { fprintf(stderr, "Something went wrong!\n"); print_error(errno); exit(1); } else { print_it(buf, punctuation, addbang, length, addfive); printf("\n"); } /* Zero and free the password. */ memset(passwd, 0, strlen(passwd)); free(passwd); return 0; }
void Auth_method_password_hash::change_credential(const lj::Uuid& target, const lj::bson::Node& data) { lj::log::format<lj::Debug>("auth_local: Finding existing user for %s") << target << lj::log::end; auto iter = credentials_by_id_.find(target); lj::bson::Node* stored_credential; if (credentials_by_id_.end() == iter) { lj::log::out<lj::Debug>( "auth_local: No user found. creating record."); stored_credential = new lj::bson::Node(); uint8_t temp_dk[1] = {0}; stored_credential->set_child(k_id_field, lj::bson::new_uuid(target)); stored_credential->set_child(k_login_field, lj::bson::new_string("")); stored_credential->set_child(k_password_field, lj::bson::new_binary(temp_dk, 1, lj::bson::Binary_type::k_bin_generic)); stored_credential->set_child(k_salt_field, lj::bson::new_binary(temp_dk, 1, lj::bson::Binary_type::k_bin_generic)); credentials_by_id_[target] = stored_credential; } else { stored_credential = (*iter).second; } lj::log::out<lj::Debug>("auth_local: calculating new derived key."); // read a new random salt. // TODO this is insecure. should use something much more secure // for creating salts. uint8_t salt_buffer[128]; for (int h = 0; h < 128; ++h) { salt_buffer[h] = (rand() & 0xFF); } lj::bson::Node* salt_node = lj::bson::new_binary( salt_buffer, 128, lj::bson::Binary_type::k_bin_generic); // The salt and password include the bson header info. This is // intentional, because it reduces the code complexity. const size_t salt_length = salt_node->size(); const uint8_t* salt = salt_node->to_value(); const size_t password_length = data[k_password_field].size(); const uint8_t* password = data[k_password_field].to_value(); // calculate the derived key. uint8_t derived_key[k_derived_key_length]; crypto_scrypt(password, password_length, salt, salt_length, k_N, k_r, k_p, derived_key, k_derived_key_length); // check if there is an old record to remove. if (credentials_by_id_.end() != iter) { const std::string old_login( lj::bson::as_string(stored_credential->nav(k_login_field))); lj::log::format<lj::Debug>("auth_local: Removing old record for %s / %s") << old_login << target << lj::log::end; credentials_by_login_.erase(old_login); } // In theory, the user cannot log in during this point. There is no entry in the // users_by_credential_ to look up this user. // TODO Existing sessions should probably be disconnected here. // Record the new credential and mapping. const std::string new_login(lj::bson::as_string(data[k_login_field])); lj::log::format<lj::Debug>("auth_local: Creating new record for %s / %s") << new_login << target << lj::log::end; stored_credential->set_child(k_login_field, lj::bson::new_string(new_login)); stored_credential->set_child(k_password_field, lj::bson::new_binary(derived_key, k_derived_key_length, lj::bson::Binary_type::k_bin_generic)); stored_credential->set_child(k_salt_field, salt_node); credentials_by_login_[new_login] = stored_credential; }
std::vector<unsigned char> decrypt_bip38(const std::vector<unsigned char> enc_data, const std::string& passwd) { //def decrypt(encrypted_privkey, passphrase, p): // //#1. Collect encrypted private key and passphrase from user. //# passed as parameters const unsigned char *data = reinterpret_cast<const unsigned char*>(enc_data.data()); unsigned char key[64]; unsigned char addresshash[4]; unsigned char encryptedhalf1[16], encryptedhalf2[16]; unsigned char decryptedhalf1[16], decryptedhalf2[16]; unsigned char derivedhalf1[32], derivedhalf2[32]; memcpy(addresshash, &data[3], 4); memcpy(encryptedhalf1, &data[7], 16); memcpy(encryptedhalf2, &data[23], 16); //#3. Derive decryption key for seedb using scrypt with passpoint, addresshash, and ownersalt //key = scrypt.hash(passphrase, addresshash, 16384, 8, p) crypto_scrypt((const uint8_t *)passwd.c_str(), passwd.length(), &addresshash[0], ADDRESSHASH_SIZE, 16384, 8, 8, key, 64); memcpy(derivedhalf1, &key[0], 32); memcpy(derivedhalf2, &key[32], 32); // //#4. Decrypt encryptedpart2 using AES256Decrypt to yield the last 8 bytes of seedb and the last 8 bytes of encryptedpart1. //Aes = aes.Aes(derivedhalf2) //decryptedhalf2 = Aes.dec(encryptedhalf2) int decrypt_len; EVP_CIPHER_CTX de; EVP_CIPHER_CTX_init(&de); EVP_DecryptInit_ex(&de, EVP_aes_256_cbc(), NULL, derivedhalf2, NULL); EVP_DecryptUpdate(&de, decryptedhalf2, &decrypt_len, encryptedhalf2, 16); //#5. Decrypt encryptedpart1 to yield the remainder of seedb. //decryptedhalf1 = Aes.dec(encryptedhalf1) EVP_DecryptInit_ex(&de, EVP_aes_256_cbc(), NULL, derivedhalf2, NULL); EVP_DecryptUpdate(&de, decryptedhalf1, &decrypt_len, encryptedhalf1, 16); //priv = decryptedhalf1 + decryptedhalf2 //priv = binascii.unhexlify('%064x' % (long(binascii.hexlify(priv), 16) ^ long(binascii.hexlify(derivedhalf1), 16))) //return priv, addresshash unsigned char priv[32]; memcpy(priv, decryptedhalf1, 16); memcpy(priv + 16, decryptedhalf2, 16); for (int i = 0; i < 32; i++) { priv[i] ^= derivedhalf1[i]; } // printf("\n"); // print_hex((char *)priv, 32); // printf("\n"); std::vector<unsigned char> out; out.assign(priv, priv + 32); return out; }
std::vector<unsigned char> encrypt_bip38(const std::vector<unsigned char> priv_key, const std::string& address, const std::string& passwd) { unsigned char key[64]; unsigned char derivedhalf1[32], derivedhalf2[32]; unsigned char encryptedhalf1[16], encryptedhalf2[16]; unsigned char part1[32], part2[32]; const unsigned char * p_address = reinterpret_cast<const unsigned char*>(address.data()); const unsigned char * p_secret = reinterpret_cast<const unsigned char*>(priv_key.data()); // 1. take the first four bytes of SHA256(SHA256()) of it. Let's call this "addresshash". // addresshash = hashlib.sha256(hashlib.sha256(address).digest()).digest()[:4] # salt unsigned char addresshash[32]; bu_Hash(addresshash, &p_address[0], 34); // #2. Derive a key from the passphrase using scrypt // # a. Parameters: passphrase is the passphrase itself encoded in UTF-8. // # addresshash came from the earlier step, n=16384, r=8, p=8, length=64 // # (n, r, p are provisional and subject to consensus) // key = scrypt.hash(passphrase, addresshash, 16384, 8, p) crypto_scrypt((const uint8_t *)passwd.c_str(), passwd.length(), &addresshash[0], ADDRESSHASH_SIZE, 16384, 8, 8, key, 64); memcpy(derivedhalf1, &key[0], 32); memcpy(derivedhalf2, &key[32], 32); // #3. Do AES256Encrypt(bitcoinprivkey[0...15] xor derivedhalf1[0...15], derivedhalf2), call the 16-byte result encryptedhalf1 // Aes = aes.Aes(derivedhalf2) // encryptedhalf1 = Aes.enc(enc.sxor(privK[:16], derivedhalf1[:16])) // for (int i=0; i < 16; i++) part1[i] = p_secret[i] ^ derivedhalf1[i]; for (int i=0; i < 16; i++) part2[i] = p_secret[i + 16] ^ derivedhalf1[i + 16]; int encrypt_len; EVP_CIPHER_CTX en; EVP_CIPHER_CTX_init(&en); EVP_EncryptInit_ex(&en, EVP_aes_256_cbc(), NULL, derivedhalf2, NULL); EVP_EncryptUpdate(&en, encryptedhalf1, &encrypt_len, part1, 16); EVP_EncryptInit_ex(&en, EVP_aes_256_cbc(), NULL, derivedhalf2, NULL); EVP_EncryptUpdate(&en, encryptedhalf2, &encrypt_len, part2, 16); // #5. The encrypted private key is the Base58Check-encoded concatenation of the following, which totals 39 bytes without Base58 checksum: // # 0x01 0x42 + flagbyte + salt + encryptedhalf1 + encryptedhalf2 // flagbyte = chr(0b11100000) # 11 no-ec 1 compressed-pub 00 future 0 ec only 00 future // privkey = ('\x01\x42' + flagbyte + addresshash + encryptedhalf1 + encryptedhalf2) // check = hashlib.sha256(hashlib.sha256(privkey).digest()).digest()[:4] // return enc.b58encode(privkey + check) unsigned char flagbyte = 0xc0;// 0b11100000; // 11 no-ec 1 compressed-pub 00 future 0 ec only 00 future unsigned char pref1 = 0x01; unsigned char pref2 = 0x42; unsigned char enc_key[128]; enc_key[0] = pref1; enc_key[1] = pref2; enc_key[2] = flagbyte; memcpy(enc_key + 3, addresshash, ADDRESSHASH_SIZE); memcpy(enc_key + 3 + ADDRESSHASH_SIZE, encryptedhalf1, 16); memcpy(enc_key + 3 + ADDRESSHASH_SIZE + 16, encryptedhalf2, 16); return std::vector<unsigned char>(&enc_key[0], &enc_key[3 + ADDRESSHASH_SIZE + 32]); }