diff options
| author | Walker Thompson <walker.thompson@urz.uni-heidelberg.de> | 2025-12-18 23:13:27 +0000 |
|---|---|---|
| committer | Walker Thompson <walker.thompson@urz.uni-heidelberg.de> | 2025-12-18 23:13:27 +0000 |
| commit | fdda56c95ae249c90b47c1a060d081db66a730da (patch) | |
| tree | 5320deba531b864f64d08883f97515b9d84850f0 /crypto.cpp | |
Initial commit
Diffstat (limited to 'crypto.cpp')
| -rw-r--r-- | crypto.cpp | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/crypto.cpp b/crypto.cpp new file mode 100644 index 0000000..818f68a --- /dev/null +++ b/crypto.cpp @@ -0,0 +1,200 @@ +extern "C" { +#include <openssl/evp.h> +#include <openssl/hmac.h> +#include <openssl/aes.h> +#include <openssl/rand.h> +} + +#include "totpgen.h" + +#define UNUSED(x) (void(x)) + +#define SALT_BYTES 8 +#define KEY_BYTES 32 +#define IV_BYTES 16 + + +#define AES_BUFFER(LEN) \ + reinterpret_cast<unsigned char *>( \ + calloc(AES_BLOCK_SIZE * (1 + ((LEN) / AES_BLOCK_SIZE)), \ + sizeof(unsigned char))); + +bool +TOTPGen::GenTOTP(std::string& secret_str) +{ + uint32_t bits, code, count, hmacsize; + uint64_t clock; + size_t length; + uint8_t msg[8], hmac[EVP_MAX_MD_SIZE]; + char totp_buf[7]; + + size_t keysize = 0; + const EVP_MD *digest = EVP_sha1(); + uint8_t *key = NULL; + + char *secret = strdup(secret_str.c_str()); + + for (count = bits = length = 0; *secret; secret++) { + if (!strchr(base32.c_str(), *secret)) { + return false; + } + bits = (bits << 5) | (strchr(base32.c_str(), *secret) - base32.c_str()); + count += 5; + + while (count >= 8) { + while (length >= keysize) { + keysize = keysize ? keysize << 1 : 64; + if (!(key = (uint8_t *)realloc(key, keysize))) { + return false; + } + } + count -= 8, key[length++] = bits >> count; + } + } + + if (length > 0) { + clock = time(NULL) / 30; + + for (count = 0; count < 8; count++) { + msg[7 - count] = clock >> 8 * count; + } + if (!HMAC(digest, key, length, msg, sizeof(msg), hmac, &hmacsize)) { + return false; + } + + for (code = count = 0; count < 4; count++) { + code += hmac[(hmac[hmacsize - 1] & 0x0f) + 3 - count] << 8 * count; + } + code &= 0x7fffffff; + + snprintf((char *)&totp_buf, 7, "%06u", code % 1000000); + } + else { + return false; + } + + TOTP = totp_buf; + TOTPField->SetLabel(TOTP); + + free(key); + + return true; +} + +void +TOTPGen::InitAES(const char *passphrase, unsigned char *salt, + unsigned char *key, unsigned char *iv) +{ + char *key_data = strdup(passphrase); + int key_text_len = strlen(passphrase); + int nrounds = 0xFF; + + EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, + reinterpret_cast<unsigned char *>(key_data), + key_text_len, nrounds, key, iv); + + free(key_data); +} + +bool +TOTPGen::EncryptSecret(std::string& secret_str) +{ + unsigned char salt[SALT_BYTES], key[KEY_BYTES], iv[IV_BYTES]; + + RAND_bytes(salt, SALT_BYTES); + + memset(&key, 0, KEY_BYTES); + memset(&iv, 0, IV_BYTES); + + InitAES(Passphrase.c_str(), reinterpret_cast<unsigned char *>(&salt), + reinterpret_cast<unsigned char *>(&key), + reinterpret_cast<unsigned char *>(&iv)); + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, + reinterpret_cast<unsigned char *>(&key), + reinterpret_cast<unsigned char *>(&iv)); + + size_t plaintext_len = strlen(secret_str.c_str()) ; + + unsigned char *plaintext = AES_BUFFER(plaintext_len); + strncpy(reinterpret_cast<char *>(plaintext), + secret_str.c_str(), plaintext_len); + + unsigned char *ciphertext = AES_BUFFER(plaintext_len); + + int len, ciphertext_len; + EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len); + ciphertext_len = len; + EVP_EncryptFinal_ex(ctx, ciphertext + len, &len); + ciphertext_len += len; + + FILE *secret_file = fopen(SecretFile.c_str(), "wb"); + if (!secret_file) { + return false; + } + + fwrite(salt, SALT_BYTES, 1, secret_file); + fwrite(ciphertext, ciphertext_len, 1, secret_file); + + fclose(secret_file); + + EVP_CIPHER_CTX_free(ctx); + free(plaintext); + free(ciphertext); + + return true; +} + + +bool +TOTPGen::DecryptSecret(void) +{ + unsigned char salt[SALT_BYTES], key[KEY_BYTES], iv[IV_BYTES]; + + memset(&key, 0, KEY_BYTES); + memset(&iv, 0, IV_BYTES); + + FILE *secret_file = fopen(SecretFile.c_str(), "rb"); + if (!secret_file) { + return false; + } + + fseek(secret_file, 0L, SEEK_END); + size_t ciphertext_len = ftell(secret_file) - SALT_BYTES; + rewind(secret_file); + + fread(&salt, SALT_BYTES, 1, secret_file); + + InitAES(Passphrase.c_str(), reinterpret_cast<unsigned char *>(&salt), + reinterpret_cast<unsigned char *>(&key), + reinterpret_cast<unsigned char *>(&iv)); + + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, + reinterpret_cast<unsigned char *>(&key), + reinterpret_cast<unsigned char *>(&iv)); + + int len; + unsigned char *ciphertext = AES_BUFFER(ciphertext_len); + unsigned char *plaintext = AES_BUFFER(ciphertext_len + 8); + + fread(ciphertext, 1, ciphertext_len, secret_file); + fclose(secret_file); + + if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) { + return false; + } + + if (!EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) { + return false; + } + + Secret = reinterpret_cast<const char *>(plaintext); + + EVP_CIPHER_CTX_free(ctx); + free(ciphertext); + free(plaintext); + + return true; +} |
