static gnutls_cipher_hd_t purple_aes_cipher_gnutls_crypt_init(guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size) { gnutls_cipher_hd_t handle; gnutls_cipher_algorithm_t algorithm; gnutls_datum_t key_info, iv_info; int ret; if (key_size == 16) algorithm = GNUTLS_CIPHER_AES_128_CBC; else if (key_size == 24) algorithm = GNUTLS_CIPHER_AES_192_CBC; else if (key_size == 32) algorithm = GNUTLS_CIPHER_AES_256_CBC; else g_return_val_if_reached(NULL); key_info.data = key; key_info.size = key_size; iv_info.data = iv; iv_info.size = PURPLE_AES_BLOCK_SIZE; ret = gnutls_cipher_init(&handle, algorithm, &key_info, &iv_info); if (ret != 0) { purple_debug_error("cipher-aes", "gnutls_cipher_init failed: %d\n", ret); return NULL; } return handle; }
static int dcrypt_gnutls_ctx_sym_init(struct dcrypt_context_symmetric *ctx, const char **error_r) { int ec; ec = gnutls_cipher_init(&ctx->ctx, ctx->cipher, &ctx->key, &ctx->iv); if(ec < 0) return dcrypt_gnutls_error(ec, error_r); return 0; }
static void cipher_bench(int algo, int size, int aead) { int ret; gnutls_cipher_hd_t ctx; void *_key, *_iv; gnutls_datum_t key, iv; int ivsize = gnutls_cipher_get_iv_size(algo); int keysize = gnutls_cipher_get_key_size(algo); int step = size * 1024; struct benchmark_st st; _key = malloc(keysize); if (_key == NULL) return; memset(_key, 0xf0, keysize); _iv = malloc(ivsize); if (_iv == NULL) return; memset(_iv, 0xf0, ivsize); iv.data = _iv; if (aead) iv.size = 12; else iv.size = ivsize; key.data = _key; key.size = keysize; printf("%16s ", gnutls_cipher_get_name(algo)); fflush(stdout); start_benchmark(&st); ret = gnutls_cipher_init(&ctx, algo, &key, &iv); if (ret < 0) { fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); goto leave; } if (aead) gnutls_cipher_add_auth(ctx, data, 1024); do { gnutls_cipher_encrypt2(ctx, data, step, data, step + 64); st.size += step; } while (benchmark_must_finish == 0); gnutls_cipher_deinit(ctx); stop_benchmark(&st, NULL, 1); leave: free(_key); free(_iv); }
CryptoRc4 crypto_rc4_init(uint8 * key, uint32 len) { CryptoRc4 rc4 = xmalloc(sizeof(*rc4)); gnutls_datum_t key_datum; key_datum.size = len; key_datum.data = key; gnutls_datum_t iv_datum; iv_datum.size = 0; iv_datum.data = NULL; int x = gnutls_cipher_init(&rc4->handle, GNUTLS_CIPHER_ARCFOUR_40, &key_datum, &iv_datum); ASSERT(!x); return rc4; }
void Cipher::set(const key_t key, mode_t mode, unsigned char *address, size_t size) { release(); bufsize = size; bufmode = mode; bufaddr = address; memcpy(&keys, key, sizeof(keys)); if(!keys.keysize) return; gnutls_datum_t keyinfo, ivinfo; keyinfo.data = keys.keybuf; keyinfo.size = keys.keysize; ivinfo.data = keys.ivbuf; ivinfo.size = keys.blksize; gnutls_cipher_init((CIPHER_CTX *)&context, (CIPHER_ID)keys.algoid, &keyinfo, &ivinfo); }
static void cipher_mac_bench(int algo, int mac_algo, int size) { int ret; gnutls_cipher_hd_t ctx; gnutls_hmac_hd_t mac_ctx; void *_key, *_iv; gnutls_datum_t key, iv; int ivsize = gnutls_cipher_get_iv_size(algo); int keysize = gnutls_cipher_get_key_size(algo); int step = size * 1024; struct benchmark_st st; void *output, *input; unsigned char c, *i; _key = malloc(keysize); if (_key == NULL) return; memset(_key, 0xf0, keysize); _iv = malloc(ivsize); if (_iv == NULL) { free(_key); return; } memset(_iv, 0xf0, ivsize); iv.data = _iv; iv.size = ivsize; key.data = _key; key.size = keysize; assert(gnutls_rnd(GNUTLS_RND_NONCE, &c, 1) >= 0); printf("%19s-%s ", gnutls_cipher_get_name(algo), gnutls_mac_get_name(mac_algo)); fflush(stdout); ALLOCM(input, MAX_MEM); ALLOC(output); i = input; start_benchmark(&st); ret = gnutls_hmac_init(&mac_ctx, mac_algo, key.data, key.size); if (ret < 0) { fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); goto leave; } ret = gnutls_cipher_init(&ctx, algo, &key, &iv); if (ret < 0) { fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); goto leave; } do { gnutls_hmac(mac_ctx, i, step); gnutls_cipher_encrypt2(ctx, i, step, output, step + 64); st.size += step; INC(input, i, step); } while (benchmark_must_finish == 0); gnutls_cipher_deinit(ctx); gnutls_hmac_deinit(mac_ctx, NULL); stop_benchmark(&st, NULL, 1); leave: FREE(input); FREE(output); free(_key); free(_iv); }
static void cipher_bench(int algo, int size, int aead) { int ret; gnutls_cipher_hd_t ctx; void *_key, *_iv; gnutls_aead_cipher_hd_t actx; gnutls_datum_t key, iv; int ivsize = gnutls_cipher_get_iv_size(algo); int keysize = gnutls_cipher_get_key_size(algo); int step = size * 1024; void *input, *output; struct benchmark_st st; unsigned char c, *i; _key = malloc(keysize); if (_key == NULL) return; memset(_key, 0xf0, keysize); _iv = malloc(ivsize); if (_iv == NULL) { free(_key); return; } memset(_iv, 0xf0, ivsize); iv.data = _iv; iv.size = ivsize; key.data = _key; key.size = keysize; printf("%24s ", gnutls_cipher_get_name(algo)); fflush(stdout); assert(gnutls_rnd(GNUTLS_RND_NONCE, &c, 1) >= 0); ALLOCM(input, MAX_MEM); ALLOCM(output, step+64); i = input; start_benchmark(&st); if (algo == GNUTLS_CIPHER_NULL) { do { force_memcpy(output, i, step); st.size += step; INC(input, i, step); } while (benchmark_must_finish == 0); } else if (aead != 0) { unsigned tag_size = gnutls_cipher_get_tag_size(algo); size_t out_size; ret = gnutls_aead_cipher_init(&actx, algo, &key); if (ret < 0) { fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); goto leave; } do { out_size = step+64; assert(gnutls_aead_cipher_encrypt(actx, iv.data, iv.size, NULL, 0, tag_size, i, step, output, &out_size) >= 0); st.size += step; INC(input, i, step); } while (benchmark_must_finish == 0); gnutls_aead_cipher_deinit(actx); } else { ret = gnutls_cipher_init(&ctx, algo, &key, &iv); if (ret < 0) { fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); goto leave; } do { gnutls_cipher_encrypt2(ctx, i, step, output, step + 64); st.size += step; INC(input, i, step); } while (benchmark_must_finish == 0); gnutls_cipher_deinit(ctx); } stop_benchmark(&st, NULL, 1); FREE(input); FREE(output); leave: free(_key); free(_iv); }
void doit(void) { int ret; unsigned int mode; gnutls_cipher_hd_t ch; gnutls_hmac_hd_t mh; gnutls_session_t session; gnutls_pubkey_t pubkey; gnutls_x509_privkey_t xprivkey; gnutls_privkey_t privkey; gnutls_datum_t key = { key16, sizeof(key16) }; gnutls_datum_t iv = { iv16, sizeof(iv16) }; fprintf(stderr, "Please note that if in FIPS140 mode, you need to assure the library's integrity prior to running this test\n"); gnutls_global_set_log_function(tls_log_func); if (debug) gnutls_global_set_log_level(4711); mode = gnutls_fips140_mode_enabled(); if (mode == 0) { success("We are not in FIPS140 mode\n"); exit(77); } ret = global_init(); if (ret < 0) { fail("Cannot initialize library\n"); } /* Try crypto.h functionality */ ret = gnutls_cipher_init(&ch, GNUTLS_CIPHER_AES_128_CBC, &key, &iv); if (ret < 0) { fail("gnutls_cipher_init failed\n"); } gnutls_cipher_deinit(ch); ret = gnutls_hmac_init(&mh, GNUTLS_MAC_SHA1, key.data, key.size); if (ret < 0) { fail("gnutls_hmac_init failed\n"); } gnutls_hmac_deinit(mh, NULL); ret = gnutls_rnd(GNUTLS_RND_NONCE, key16, sizeof(key16)); if (ret < 0) { fail("gnutls_rnd failed\n"); } ret = gnutls_pubkey_init(&pubkey); if (ret < 0) { fail("gnutls_pubkey_init failed\n"); } gnutls_pubkey_deinit(pubkey); ret = gnutls_privkey_init(&privkey); if (ret < 0) { fail("gnutls_privkey_init failed\n"); } gnutls_privkey_deinit(privkey); ret = gnutls_x509_privkey_init(&xprivkey); if (ret < 0) { fail("gnutls_privkey_init failed\n"); } gnutls_x509_privkey_deinit(xprivkey); ret = gnutls_init(&session, 0); if (ret < 0) { fail("gnutls_init failed\n"); } gnutls_deinit(session); /* Test when FIPS140 is set to error state */ _gnutls_lib_simulate_error(); /* Try crypto.h functionality */ ret = gnutls_cipher_init(&ch, GNUTLS_CIPHER_AES_128_CBC, &key, &iv); if (ret >= 0) { fail("gnutls_cipher_init succeeded when in FIPS140 error state\n"); } ret = gnutls_hmac_init(&mh, GNUTLS_MAC_SHA1, key.data, key.size); if (ret >= 0) { fail("gnutls_hmac_init succeeded when in FIPS140 error state\n"); } ret = gnutls_rnd(GNUTLS_RND_NONCE, key16, sizeof(key16)); if (ret >= 0) { fail("gnutls_rnd succeeded when in FIPS140 error state\n"); } ret = gnutls_pubkey_init(&pubkey); if (ret >= 0) { fail("gnutls_pubkey_init succeeded when in FIPS140 error state\n"); } ret = gnutls_privkey_init(&privkey); if (ret >= 0) { fail("gnutls_privkey_init succeeded when in FIPS140 error state\n"); } ret = gnutls_x509_privkey_init(&xprivkey); if (ret >= 0) { fail("gnutls_x509_privkey_init succeeded when in FIPS140 error state\n"); } ret = gnutls_init(&session, 0); if (ret >= 0) { fail("gnutls_init succeeded when in FIPS140 error state\n"); } gnutls_global_deinit(); return; }
gchar *password_decrypt_gnutls(const gchar *password, const gchar *decryption_passphrase) { gchar **tokens, *tmp; gnutls_cipher_algorithm_t algo; gnutls_cipher_hd_t handle; gnutls_datum_t key, iv; int keylen, blocklen, ret; gsize len; unsigned char *buf; guint rounds; size_t commapos; g_return_val_if_fail(password != NULL, NULL); g_return_val_if_fail(decryption_passphrase != NULL, NULL); tokens = g_strsplit_set(password, "{}", 3); /* Parse the string, retrieving algorithm and encrypted data. * We expect "{algorithm,rounds}base64encodedciphertext". */ if (tokens[0] == NULL || strlen(tokens[0]) != 0 || tokens[1] == NULL || strlen(tokens[1]) == 0 || tokens[2] == NULL || strlen(tokens[2]) == 0) { debug_print("Garbled password string.\n"); g_strfreev(tokens); return NULL; } commapos = strcspn(tokens[1], ","); if (commapos == strlen(tokens[1]) || commapos == 0) { debug_print("Garbled algorithm substring.\n"); g_strfreev(tokens); return NULL; } buf = g_strndup(tokens[1], commapos); if ((algo = gnutls_cipher_get_id(buf)) == GNUTLS_CIPHER_UNKNOWN) { debug_print("Password string has unknown algorithm: '%s'\n", buf); g_free(buf); g_strfreev(tokens); return NULL; } g_free(buf); if ((rounds = atoi(tokens[1] + commapos + 1)) <= 0) { debug_print("Invalid number of rounds: %d\n", rounds); g_strfreev(tokens); return NULL; } /* ivlen = gnutls_cipher_get_iv_size(algo); */ keylen = gnutls_cipher_get_key_size(algo); blocklen = gnutls_cipher_get_block_size(algo); /* digestlen = gnutls_hash_get_len(digest); */ /* Take the passphrase and compute a key derivation of suitable * length to be used as encryption key for our block cipher. */ key.data = _make_key_deriv(decryption_passphrase, rounds, keylen); key.size = keylen; /* Prepare random IV for cipher */ iv.data = malloc(IVLEN); iv.size = IVLEN; if (!get_random_bytes(iv.data, IVLEN)) { g_free(key.data); g_free(iv.data); g_strfreev(tokens); return NULL; } /* Prepare encrypted password string for decryption. */ tmp = g_base64_decode(tokens[2], &len); g_strfreev(tokens); /* Initialize the decryption */ ret = gnutls_cipher_init(&handle, algo, &key, &iv); if (ret < 0) { debug_print("Cipher init failed: %s\n", gnutls_strerror(ret)); g_free(key.data); g_free(iv.data); return NULL; } buf = malloc(BUFSIZE + blocklen); memset(buf, 0, BUFSIZE + blocklen); ret = gnutls_cipher_decrypt2(handle, tmp, len, buf, BUFSIZE + blocklen); if (ret < 0) { debug_print("Decryption failed: %s\n", gnutls_strerror(ret)); g_free(key.data); g_free(iv.data); g_free(buf); gnutls_cipher_deinit(handle); return NULL; } /* Cleanup */ gnutls_cipher_deinit(handle); g_free(key.data); g_free(iv.data); tmp = g_strndup(buf + blocklen, MIN(strlen(buf + blocklen), BUFSIZE)); g_free(buf); return tmp; }
gchar *password_encrypt_gnutls(const gchar *password, const gchar *encryption_passphrase) { /* Another, slightly inferior combination is AES-128-CBC + SHA-256. * Any block cipher in CBC mode with keysize N and a hash algo with * digest length 2*N would do. */ gnutls_cipher_algorithm_t algo = GNUTLS_CIPHER_AES_256_CBC; gnutls_cipher_hd_t handle; gnutls_datum_t key, iv; int keylen, blocklen, ret; unsigned char *buf, *encbuf, *base, *output; guint rounds = prefs_common_get_prefs()->master_passphrase_pbkdf2_rounds; g_return_val_if_fail(password != NULL, NULL); g_return_val_if_fail(encryption_passphrase != NULL, NULL); /* ivlen = gnutls_cipher_get_iv_size(algo);*/ keylen = gnutls_cipher_get_key_size(algo); blocklen = gnutls_cipher_get_block_size(algo); /* digestlen = gnutls_hash_get_len(digest); */ /* Take the passphrase and compute a key derivation of suitable * length to be used as encryption key for our block cipher. */ key.data = _make_key_deriv(encryption_passphrase, rounds, keylen); key.size = keylen; /* Prepare random IV for cipher */ iv.data = malloc(IVLEN); iv.size = IVLEN; if (!get_random_bytes(iv.data, IVLEN)) { g_free(key.data); g_free(iv.data); return NULL; } /* Initialize the encryption */ ret = gnutls_cipher_init(&handle, algo, &key, &iv); if (ret < 0) { g_free(key.data); g_free(iv.data); return NULL; } /* Fill buf with one block of random data, our password, pad the * rest with zero bytes. */ buf = malloc(BUFSIZE + blocklen); memset(buf, 0, BUFSIZE); if (!get_random_bytes(buf, blocklen)) { g_free(buf); g_free(key.data); g_free(iv.data); gnutls_cipher_deinit(handle); return NULL; } memcpy(buf + blocklen, password, strlen(password)); /* Encrypt into encbuf */ encbuf = malloc(BUFSIZE + blocklen); memset(encbuf, 0, BUFSIZE + blocklen); ret = gnutls_cipher_encrypt2(handle, buf, BUFSIZE + blocklen, encbuf, BUFSIZE + blocklen); if (ret < 0) { g_free(key.data); g_free(iv.data); g_free(buf); g_free(encbuf); gnutls_cipher_deinit(handle); return NULL; } /* Cleanup */ gnutls_cipher_deinit(handle); g_free(key.data); g_free(iv.data); g_free(buf); /* And finally prepare the resulting string: * "{algorithm,rounds}base64encodedciphertext" */ base = g_base64_encode(encbuf, BUFSIZE); g_free(encbuf); output = g_strdup_printf("{%s,%d}%s", gnutls_cipher_get_name(algo), rounds, base); g_free(base); return output; }
static void cipher_bench (int algo, int size) { int ret; gnutls_cipher_hd_t ctx; void *_key, *_iv; gnutls_datum_t key, iv; struct timespec start, stop; double secs; double data_size = 0; double dspeed, ddata; int blocksize = gnutls_cipher_get_block_size (algo); int keysize = gnutls_cipher_get_key_size (algo); char metric[16]; _key = malloc (keysize); if (_key == NULL) return; memset (_key, 0xf0, keysize); _iv = malloc (blocksize); if (_iv == NULL) return; memset (_iv, 0xf0, blocksize); iv.data = _iv; iv.size = blocksize; key.data = _key; key.size = keysize; printf ("Checking %s (%dkb payload)... ", gnutls_cipher_get_name (algo), size); fflush (stdout); must_finish = 0; alarm (5); gettime (&start); ret = gnutls_cipher_init (&ctx, algo, &key, &iv); if (ret < 0) { fprintf (stderr, "error: %s\n", gnutls_strerror (ret)); goto leave; } do { gnutls_cipher_encrypt (ctx, data, size * 1024); data_size += size * 1024; } while (must_finish == 0); gnutls_cipher_deinit (ctx); gettime (&stop); secs = (stop.tv_sec * 1000 + stop.tv_nsec / (1000 * 1000) - (start.tv_sec * 1000 + start.tv_nsec / (1000 * 1000))); secs /= 1000; value2human (data_size, secs, &ddata, &dspeed, metric); printf ("Encrypted %.2f %s in %.2f secs: ", ddata, metric, secs); printf ("%.2f %s/sec\n", dspeed, metric); leave: free (_key); free (_iv); }
/** * gnutls_x509_privkey_import_openssl: * @key: The structure to store the parsed key * @data: The DER or PEM encoded key. * @password: the password to decrypt the key (if it is encrypted). * * This function will convert the given PEM encrypted to * the native gnutls_x509_privkey_t format. The * output will be stored in @key. * * The @password should be in ASCII. If the password is not provided * or wrong then %GNUTLS_E_DECRYPTION_FAILED will be returned. * * If the Certificate is PEM encoded it should have a header of * "PRIVATE KEY" and the "DEK-Info" header. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_x509_privkey_import_openssl(gnutls_x509_privkey_t key, const gnutls_datum_t * data, const char *password) { gnutls_cipher_hd_t handle; gnutls_cipher_algorithm_t cipher = GNUTLS_CIPHER_UNKNOWN; gnutls_datum_t b64_data; gnutls_datum_t salt, enc_key; unsigned char *key_data; size_t key_data_size; const char *pem_header = (void *) data->data; const char *pem_header_start = (void *) data->data; ssize_t pem_header_size; int ret; unsigned int i, iv_size, l; pem_header_size = data->size; pem_header = memmem(pem_header, pem_header_size, "PRIVATE KEY---", 14); if (pem_header == NULL) { gnutls_assert(); return GNUTLS_E_PARSING_ERROR; } pem_header_size -= (ptrdiff_t) (pem_header - pem_header_start); pem_header = memmem(pem_header, pem_header_size, "DEK-Info: ", 10); if (pem_header == NULL) { gnutls_assert(); return GNUTLS_E_PARSING_ERROR; } pem_header_size = data->size - (ptrdiff_t) (pem_header - pem_header_start) - 10; pem_header += 10; for (i = 0; i < sizeof(pem_ciphers) / sizeof(pem_ciphers[0]); i++) { l = strlen(pem_ciphers[i].name); if (!strncmp(pem_header, pem_ciphers[i].name, l) && pem_header[l] == ',') { pem_header += l + 1; cipher = pem_ciphers[i].cipher; break; } } if (cipher == GNUTLS_CIPHER_UNKNOWN) { _gnutls_debug_log ("Unsupported PEM encryption type: %.10s\n", pem_header); gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } iv_size = gnutls_cipher_get_iv_size(cipher); salt.size = iv_size; salt.data = gnutls_malloc(salt.size); if (!salt.data) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); for (i = 0; i < salt.size * 2; i++) { unsigned char x; const char *c = &pem_header[i]; if (*c >= '0' && *c <= '9') x = (*c) - '0'; else if (*c >= 'A' && *c <= 'F') x = (*c) - 'A' + 10; else { gnutls_assert(); /* Invalid salt in encrypted PEM file */ ret = GNUTLS_E_INVALID_REQUEST; goto out_salt; } if (i & 1) salt.data[i / 2] |= x; else salt.data[i / 2] = x << 4; } pem_header += salt.size * 2; if (*pem_header != '\r' && *pem_header != '\n') { gnutls_assert(); ret = GNUTLS_E_INVALID_REQUEST; goto out_salt; } while (*pem_header == '\n' || *pem_header == '\r') pem_header++; ret = _gnutls_base64_decode((const void *) pem_header, pem_header_size, &b64_data); if (ret < 0) { gnutls_assert(); goto out_salt; } if (b64_data.size < 16) { /* Just to be sure our parsing is OK */ gnutls_assert(); ret = GNUTLS_E_PARSING_ERROR; goto out_b64; } ret = GNUTLS_E_MEMORY_ERROR; enc_key.size = gnutls_cipher_get_key_size(cipher); enc_key.data = gnutls_malloc(enc_key.size); if (!enc_key.data) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto out_b64; } key_data_size = b64_data.size; key_data = gnutls_malloc(key_data_size); if (!key_data) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto out_enc_key; } while (1) { memcpy(key_data, b64_data.data, key_data_size); ret = openssl_hash_password(password, &enc_key, &salt); if (ret < 0) { gnutls_assert(); goto out; } ret = gnutls_cipher_init(&handle, cipher, &enc_key, &salt); if (ret < 0) { gnutls_assert(); gnutls_cipher_deinit(handle); goto out; } ret = gnutls_cipher_decrypt(handle, key_data, key_data_size); gnutls_cipher_deinit(handle); if (ret < 0) { gnutls_assert(); goto out; } /* We have to strip any padding to accept it. So a bit more ASN.1 parsing for us. */ if (key_data[0] == 0x30) { gnutls_datum_t key_datum; unsigned int blocksize = gnutls_cipher_get_block_size(cipher); unsigned int keylen = key_data[1]; unsigned int ofs = 2; if (keylen & 0x80) { int lenlen = keylen & 0x7f; keylen = 0; if (lenlen > 3) { gnutls_assert(); goto fail; } while (lenlen) { keylen <<= 8; keylen |= key_data[ofs++]; lenlen--; } } keylen += ofs; /* If there appears to be more padding than required, fail */ if (key_data_size - keylen > blocksize) { gnutls_assert(); goto fail; } /* If the padding bytes aren't all equal to the amount of padding, fail */ ofs = keylen; while (ofs < key_data_size) { if (key_data[ofs] != key_data_size - keylen) { gnutls_assert(); goto fail; } ofs++; } key_datum.data = key_data; key_datum.size = keylen; ret = gnutls_x509_privkey_import(key, &key_datum, GNUTLS_X509_FMT_DER); if (ret == 0) goto out; } fail: ret = GNUTLS_E_DECRYPTION_FAILED; goto out; } out: zeroize_key(key_data, key_data_size); gnutls_free(key_data); out_enc_key: _gnutls_free_key_datum(&enc_key); out_b64: gnutls_free(b64_data.data); out_salt: gnutls_free(salt.data); return ret; }
char * crypto_encrypt (const char *cipher, const GByteArray *data, const char *iv, const gsize iv_len, const char *key, gsize key_len, gsize *out_len, GError **error) { gnutls_cipher_hd_t ctx; gnutls_datum_t key_dt, iv_dt; int err; int cipher_mech; char *output = NULL; gboolean success = FALSE; gsize padded_buf_len, pad_len, output_len; char *padded_buf = NULL; guint32 i; gsize salt_len; if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) { cipher_mech = GNUTLS_CIPHER_3DES_CBC; salt_len = SALT_LEN; } else if (!strcmp (cipher, CIPHER_AES_CBC)) { cipher_mech = GNUTLS_CIPHER_AES_128_CBC; salt_len = iv_len; } else { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERR_UNKNOWN_CIPHER, _("Private key cipher '%s' was unknown."), cipher); return NULL; } /* If data->len % ivlen == 0, then we add another complete block * onto the end so that the decrypter knows there's padding. */ pad_len = iv_len - (data->len % iv_len); output_len = padded_buf_len = data->len + pad_len; padded_buf = g_malloc0 (padded_buf_len); memcpy (padded_buf, data->data, data->len); for (i = 0; i < pad_len; i++) padded_buf[data->len + i] = (guint8) (pad_len & 0xFF); output = g_malloc0 (output_len); key_dt.data = (unsigned char *) key; key_dt.size = key_len; iv_dt.data = (unsigned char *) iv; iv_dt.size = iv_len; err = gnutls_cipher_init (&ctx, cipher_mech, &key_dt, &iv_dt); if (err < 0) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERR_CIPHER_INIT_FAILED, _("Failed to initialize the encryption cipher context: %s (%s)"), gnutls_strerror_name (err), gnutls_strerror (err)); goto out; } err = gnutls_cipher_encrypt2 (ctx, padded_buf, padded_buf_len, output, output_len); if (err < 0) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED, _("Failed to encrypt the data: %s (%s)"), gnutls_strerror_name (err), gnutls_strerror (err)); goto out; } *out_len = output_len; success = TRUE; out: if (padded_buf) { memset (padded_buf, 0, padded_buf_len); g_free (padded_buf); padded_buf = NULL; } if (!success) { if (output) { /* Don't expose key material */ memset (output, 0, output_len); g_free (output); output = NULL; } } gnutls_cipher_deinit (ctx); return output; }
char * crypto_decrypt (const char *cipher, int key_type, GByteArray *data, const char *iv, const gsize iv_len, const char *key, const gsize key_len, gsize *out_len, GError **error) { gnutls_cipher_hd_t ctx; gnutls_datum_t key_dt, iv_dt; int err; int cipher_mech, i; char *output = NULL; gboolean success = FALSE; gsize pad_len, real_iv_len; if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) { cipher_mech = GNUTLS_CIPHER_3DES_CBC; real_iv_len = SALT_LEN; } else if (!strcmp (cipher, CIPHER_DES_CBC)) { cipher_mech = GNUTLS_CIPHER_DES_CBC; real_iv_len = SALT_LEN; } else if (!strcmp (cipher, CIPHER_AES_CBC)) { cipher_mech = GNUTLS_CIPHER_AES_128_CBC; real_iv_len = 16; } else { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERR_UNKNOWN_CIPHER, _("Private key cipher '%s' was unknown."), cipher); return NULL; } if (iv_len < real_iv_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERR_RAW_IV_INVALID, _("Invalid IV length (must be at least %zd)."), real_iv_len); return NULL; } output = g_malloc0 (data->len); key_dt.data = (unsigned char *) key; key_dt.size = key_len; iv_dt.data = (unsigned char *) iv; iv_dt.size = iv_len; err = gnutls_cipher_init (&ctx, cipher_mech, &key_dt, &iv_dt); if (err < 0) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERR_CIPHER_INIT_FAILED, _("Failed to initialize the decryption cipher context: %s (%s)"), gnutls_strerror_name (err), gnutls_strerror (err)); goto out; } err = gnutls_cipher_decrypt2 (ctx, data->data, data->len, output, data->len); if (err < 0) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED, _("Failed to decrypt the private key: %s (%s)"), gnutls_strerror_name (err), gnutls_strerror (err)); goto out; } pad_len = output[data->len - 1]; /* Check if the padding at the end of the decrypted data is valid */ if (pad_len == 0 || pad_len > real_iv_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED, _("Failed to decrypt the private key: unexpected padding length.")); goto out; } /* Validate tail padding; last byte is the padding size, and all pad bytes * should contain the padding size. */ for (i = 1; i <= pad_len; ++i) { if (output[data->len - i] != pad_len) { g_set_error (error, NM_CRYPTO_ERROR, NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED, _("Failed to decrypt the private key.")); goto out; } } *out_len = data->len - pad_len; success = TRUE; out: if (!success) { if (output) { /* Don't expose key material */ memset (output, 0, data->len); g_free (output); output = NULL; } } gnutls_cipher_deinit (ctx); return output; }