int main() { uint8_t key[1024]; char *password = "******"; char *salt = "salt"; int i, fails; struct test *t; fails = 0; memset(key, 0, 1024); bcrypt_pbkdf("password", 8, "salt", 4, key, 88, 4); if (key[88] || key[89] || key[90]) { printf("OVERWRITE\n"); fails++; } for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { t = &tests[i]; bcrypt_pbkdf(t->password, t->passlen, t->salt, t->saltlen, key, t->keylen, t->rounds); if (memcmp(key, t->key, t->keylen) != 0) { printf("test %d FAILED\n", i); printf("expected:\n"); printkey(t->key, t->keylen); printf("result:\n"); printkey(key, t->keylen); fails++; } } return fails; }
static void kdf(uint8_t *salt, size_t saltlen, int rounds, kdf_allowstdin allowstdin, kdf_confirm confirm, uint8_t *key, size_t keylen) { char pass[1024]; int rppflags = RPP_ECHO_OFF; if (rounds == 0) { memset(key, 0, keylen); return; } if (allowstdin.v && !isatty(STDIN_FILENO)) rppflags |= RPP_STDIN; if (!readpassphrase("passphrase: ", pass, sizeof(pass), rppflags)) errx(1, "unable to read passphrase"); if (strlen(pass) == 0) errx(1, "please provide a password"); if (confirm.v && !(rppflags & RPP_STDIN)) { char pass2[1024]; if (!readpassphrase("confirm passphrase: ", pass2, sizeof(pass2), rppflags)) errx(1, "unable to read passphrase"); if (strcmp(pass, pass2) != 0) errx(1, "passwords don't match"); explicit_bzero(pass2, sizeof(pass2)); } if (bcrypt_pbkdf(pass, strlen(pass), salt, saltlen, key, keylen, rounds) == -1) errx(1, "bcrypt pbkdf"); explicit_bzero(pass, sizeof(pass)); }
static int crypt_all(int *pcount, struct db_salt *salt) { const int count = *pcount; int index = 0; #ifdef _OPENMP #pragma omp parallel for for (index = 0; index < count; index++) #endif { if (cur_salt->cipher == 0) { unsigned char key[24] = {0}; unsigned char out[N]; DES_cblock key1, key2, key3; DES_cblock ivec; DES_key_schedule ks1, ks2, ks3; generate24key_bytes((unsigned char*)saved_key[index], key); memset(out, 0, SAFETY_FACTOR); memcpy(key1, key, 8); memcpy(key2, key + 8, 8); memcpy(key3, key + 16, 8); DES_set_key((DES_cblock *) key1, &ks1); DES_set_key((DES_cblock *) key2, &ks2); DES_set_key((DES_cblock *) key3, &ks3); memcpy(ivec, cur_salt->salt, 8); // DES_ede3_cbc_encrypt(cur_salt->ct, out, cur_salt->ctl, &ks1, &ks2, &ks3, &ivec, DES_DECRYPT); DES_ede3_cbc_encrypt(cur_salt->ct, out, SAFETY_FACTOR, &ks1, &ks2, &ks3, &ivec, DES_DECRYPT); DES_ede3_cbc_encrypt(cur_salt->ct + cur_salt->ctl - 32, out + cur_salt->ctl - 32, 32, &ks1, &ks2, &ks3, &ivec, DES_DECRYPT); if (check_padding_and_structure(out, cur_salt->ctl) == 0) cracked[index] = 1; else cracked[index] = 0; } else if (cur_salt->cipher == 1) { unsigned char key[16] = {0}; unsigned char out[N]; // unsigned char out[N] = {0}; AES_KEY akey; unsigned char iv[16]; memcpy(iv, cur_salt->salt, 16); memset(out, 0, SAFETY_FACTOR); memset(out + cur_salt->ctl - 32, 0, 32); generate16key_bytes((unsigned char*)saved_key[index], key); AES_set_decrypt_key(key, 128, &akey); // AES_cbc_encrypt(cur_salt->ct, out, cur_salt->ctl, &akey, iv, AES_DECRYPT); // dirty hack! AES_cbc_encrypt(cur_salt->ct, out, SAFETY_FACTOR, &akey, iv, AES_DECRYPT); // are starting SAFETY_FACTOR bytes enough? // decrypting 1 blocks (16 bytes) is enough for correct padding check memcpy(iv, cur_salt->ct + cur_salt->ctl - 32, 16); AES_cbc_encrypt(cur_salt->ct + cur_salt->ctl - 16, out + cur_salt->ctl - 16, 16, &akey, iv, AES_DECRYPT); if (check_padding_and_structure(out, cur_salt->ctl) == 0) cracked[index] = 1; else cracked[index] = 0; } else { /* new ssh key format handling */ unsigned char key[32+16] = {0}; unsigned char out[32] = {0}; AES_KEY akey; unsigned char iv[16]; // derive (key length + iv length) bytes bcrypt_pbkdf(saved_key[index], strlen(saved_key[index]), cur_salt->salt, 16, key, 32 + 16, cur_salt->rounds); AES_set_decrypt_key(key, 256, &akey); memcpy(iv, key + 32, 16); AES_cbc_encrypt(cur_salt->ct + cur_salt->ctl - 32, out, 32, &akey, iv, AES_DECRYPT); // decrypt 2 blocks if (check_padding_only(out + 16, 16) == 0) /* always check the last block (16 bytes) */ cracked[index] = 1; else cracked[index] = 0; } } return count; }
/** @internal * @brief encrypts an ed25519 private key blob * */ static int pki_private_key_encrypt(ssh_buffer privkey_buffer, const char* passphrase, const char *ciphername, const char *kdfname, ssh_auth_callback auth_fn, void *auth_data, uint32_t rounds, ssh_string salt) { struct ssh_cipher_struct *ciphers = ssh_get_ciphertab(); struct ssh_cipher_struct cipher; uint8_t key_material[128]; size_t key_material_len; char passphrase_buffer[128]; int rc; int i; uint8_t padding = 1; int cmp; cmp = strcmp(ciphername, "none"); if (cmp == 0){ /* no encryption required */ return SSH_OK; } for (i = 0; ciphers[i].name != NULL; i++) { cmp = strcmp(ciphername, ciphers[i].name); if (cmp == 0){ memcpy(&cipher, &ciphers[i], sizeof(cipher)); break; } } if (ciphers[i].name == NULL){ SSH_LOG(SSH_LOG_WARN, "Unsupported cipher %s", ciphername); return SSH_ERROR; } cmp = strcmp(kdfname, "bcrypt"); if (cmp != 0){ SSH_LOG(SSH_LOG_WARN, "Unsupported KDF %s", kdfname); return SSH_ERROR; } while (ssh_buffer_get_len(privkey_buffer) % cipher.blocksize != 0) { rc = buffer_add_u8(privkey_buffer, padding); if (rc < 0) { return SSH_ERROR; } padding++; } /* We need material for key (keysize bits / 8) and IV (blocksize) */ key_material_len = cipher.keysize/8 + cipher.blocksize; if (key_material_len > sizeof(key_material)){ ssh_pki_log("Key material too big"); return SSH_ERROR; } ssh_pki_log("Encryption: %d key, %d IV, %d rounds, %zu bytes salt", cipher.keysize/8, cipher.blocksize, rounds, ssh_string_len(salt)); if (passphrase == NULL){ if (auth_fn == NULL){ ssh_pki_log("No passphrase provided"); return SSH_ERROR; } rc = auth_fn("Passphrase", passphrase_buffer, sizeof(passphrase_buffer), 0, 0, auth_data); if (rc != SSH_OK){ return SSH_ERROR; } passphrase = passphrase_buffer; } rc = bcrypt_pbkdf(passphrase, strlen(passphrase), ssh_string_data(salt), ssh_string_len(salt), key_material, key_material_len, rounds); if (rc < 0){ return SSH_ERROR; } cipher.set_encrypt_key(&cipher, key_material, key_material + cipher.keysize/8); cipher.encrypt(&cipher, ssh_buffer_get_begin(privkey_buffer), ssh_buffer_get_begin(privkey_buffer), ssh_buffer_get_len(privkey_buffer)); ssh_cipher_clear(&cipher); BURN_BUFFER(passphrase_buffer, sizeof(passphrase_buffer)); return SSH_OK; }
/** * @brief decrypts an encrypted ed25519 private key blob * */ static int pki_private_key_decrypt(ssh_string blob, const char* passphrase, const char *ciphername, const char *kdfname, ssh_string kdfoptions, ssh_auth_callback auth_fn, void *auth_data) { struct ssh_cipher_struct *ciphers = ssh_get_ciphertab(); struct ssh_cipher_struct cipher; uint8_t key_material[128]; char passphrase_buffer[128]; size_t key_material_len; ssh_buffer buffer; ssh_string salt; uint32_t rounds; int cmp; int rc; int i; cmp = strcmp(ciphername, "none"); if (cmp == 0){ /* no decryption required */ return SSH_OK; } for (i = 0; ciphers[i].name != NULL; i++) { cmp = strcmp(ciphername, ciphers[i].name); if (cmp == 0){ memcpy(&cipher, &ciphers[i], sizeof(cipher)); break; } } if (ciphers[i].name == NULL){ SSH_LOG(SSH_LOG_WARN, "Unsupported cipher %s", ciphername); return SSH_ERROR; } cmp = strcmp(kdfname, "bcrypt"); if (cmp != 0) { SSH_LOG(SSH_LOG_WARN, "Unsupported KDF %s", kdfname); return SSH_ERROR; } if (ssh_string_len(blob) % cipher.blocksize != 0) { SSH_LOG(SSH_LOG_WARN, "Encrypted string not multiple of blocksize: %zu", ssh_string_len(blob)); return SSH_ERROR; } buffer = ssh_buffer_new(); if (buffer == NULL){ return SSH_ERROR; } rc = ssh_buffer_add_data(buffer, ssh_string_data(kdfoptions), ssh_string_len(kdfoptions)); if (rc != SSH_ERROR){ rc = ssh_buffer_unpack(buffer, "Sd", &salt, &rounds); } ssh_buffer_free(buffer); if (rc == SSH_ERROR){ return SSH_ERROR; } /* We need material for key (keysize bits / 8) and IV (blocksize) */ key_material_len = cipher.keysize/8 + cipher.blocksize; if (key_material_len > sizeof(key_material)) { ssh_pki_log("Key material too big"); return SSH_ERROR; } ssh_pki_log("Decryption: %d key, %d IV, %d rounds, %zu bytes salt", cipher.keysize/8, cipher.blocksize, rounds, ssh_string_len(salt)); if (passphrase == NULL) { if (auth_fn == NULL) { SAFE_FREE(salt); ssh_pki_log("No passphrase provided"); return SSH_ERROR; } rc = auth_fn("Passphrase", passphrase_buffer, sizeof(passphrase_buffer), 0, 0, auth_data); if (rc != SSH_OK) { SAFE_FREE(salt); return SSH_ERROR; } passphrase = passphrase_buffer; } rc = bcrypt_pbkdf(passphrase, strlen(passphrase), ssh_string_data(salt), ssh_string_len(salt), key_material, key_material_len, rounds); SAFE_FREE(salt); if (rc < 0){ return SSH_ERROR; } BURN_BUFFER(passphrase_buffer, sizeof(passphrase_buffer)); cipher.set_decrypt_key(&cipher, key_material, key_material + cipher.keysize/8); cipher.decrypt(&cipher, ssh_string_data(blob), ssh_string_data(blob), ssh_string_len(blob)); ssh_cipher_clear(&cipher); return SSH_OK; }