handle->auth = cc->auth;
handle->tag = cc->tag;
handle->setiv = cc->setiv;
+ handle->getiv = cc->getiv;
/* if cc->init() returns GNUTLS_E_NEED_FALLBACK we
* use the default ciphers */
handle->auth = _gnutls_cipher_ops.auth;
handle->tag = _gnutls_cipher_ops.tag;
handle->setiv = _gnutls_cipher_ops.setiv;
+ handle->getiv = _gnutls_cipher_ops.getiv;
/* otherwise use generic cipher interface
*/
typedef int (*cipher_auth_func) (void *hd, const void *data, size_t);
typedef int (*cipher_setiv_func) (void *hd, const void *iv, size_t);
+typedef int (*cipher_getiv_func) (void *hd, void *iv, size_t);
typedef void (*cipher_tag_func) (void *hd, void *tag, size_t);
cipher_auth_func auth;
cipher_tag_func tag;
cipher_setiv_func setiv;
+ cipher_getiv_func getiv;
cipher_deinit_func deinit;
} cipher_hd_st;
return handle->setiv(handle->handle, iv, ivlen);
}
+inline static int _gnutls_cipher_getiv(const cipher_hd_st * handle,
+ void *iv, size_t ivlen)
+{
+ if (unlikely(handle == NULL || handle->handle == NULL ||
+ handle->getiv == NULL))
+ return GNUTLS_E_INVALID_REQUEST;
+
+ return handle->getiv(handle->handle, iv, ivlen);
+}
+
inline static int
_gnutls_cipher_encrypt2(const cipher_hd_st * handle, const void *text,
size_t textlen, void *ciphertext,
int _gnutls_cipher_exists(gnutls_cipher_algorithm_t cipher);
+int _gnutls_cipher_get_iv(gnutls_cipher_hd_t handle, void *iv,
+ size_t ivlen);
+
#define _gnutls_cipher_is_aead(h) _gnutls_cipher_algo_is_aead((h)->e)
/* returns the tag in AUTHENC ciphers */
}
}
+/*-
+ * _gnutls_cipher_get_iv:
+ * @handle: is a #gnutls_cipher_hd_t type
+ * @iv: the IV to set
+ * @ivlen: the length of the IV
+ *
+ * This function will retrieve the internally calculated IV value. It is
+ * intended to be used for modes like CFB. @iv must have @ivlen length
+ * at least.
+ *
+ * This is solely for validation purposes of our crypto
+ * implementation. For other purposes, the IV can be typically
+ * calculated from the initial IV value and the subsequent ciphertext
+ * values. As such, this function only works with the internally
+ * registered ciphers.
+ *
+ * Returns: The length of IV or a negative error code on error.
+ *
+ * Since: 3.6.8
+ -*/
+int
+_gnutls_cipher_get_iv(gnutls_cipher_hd_t handle, void *iv, size_t ivlen)
+{
+ api_cipher_hd_st *h = handle;
+
+ return _gnutls_cipher_getiv(&h->ctx_enc, iv, ivlen);
+}
+
/**
* gnutls_cipher_encrypt:
* @handle: is a #gnutls_cipher_hd_t type
gnutls_cipher_init_func init;
gnutls_cipher_setkey_func setkey;
gnutls_cipher_setiv_func setiv;
+ gnutls_cipher_getiv_func getiv;
gnutls_cipher_encrypt_func encrypt;
gnutls_cipher_decrypt_func decrypt;
gnutls_cipher_aead_encrypt_func aead_encrypt;
const uint8_t *iv;
unsigned int iv_size;
+
+ const uint8_t *internal_iv;
+ unsigned int internal_iv_size;
};
struct cipher_aead_vectors_st {
"\x32\xb9",
STR(iv, iv_size,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"),
+ /* the least significant 16 bytes of ciphertext */
+ STR(internal_iv, internal_iv_size,
+ "\x42\x4c\x9c\x0d\xd4\x36\xba\xce\x9e\x0e\xd4\x58\x6a\x4f\x32\xb9"),
},
};
"\x67\x8a",
STR(iv, iv_size,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"),
+ /* the least significant 16 bytes of ciphertext */
+ STR(internal_iv, internal_iv_size,
+ "\x52\x1e\xf0\xa9\x05\xca\x44\xcd\x05\x7c\xbf\x0d\x47\xa0\x67\x8a"),
},
};
"\x97\x00",
STR(iv, iv_size,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"),
+ /* the least significant 16 bytes of ciphertext */
+ STR(internal_iv, internal_iv_size,
+ "\x1a\x85\x20\xa6\x4d\xb5\x5f\xcc\x8a\xc5\x54\x84\x4e\x88\x97\x00"),
},
};
}
}
+ /* check the internal IV */
+ if (vectors[i].internal_iv_size > 0) {
+ ret = _gnutls_cipher_get_iv(hd, tmp, sizeof(tmp));
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+
+ if (memcmp(tmp, vectors[i].internal_iv, ret) != 0) {
+ _gnutls_debug_log("%s vector %d internal IV check failed!\n",
+ gnutls_cipher_get_name(cipher),
+ i);
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+ }
+
gnutls_cipher_deinit(hd);
}
goto error;
}
+ ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_CFB8);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
/* Digest tests */
ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHA3_224);
if (ret < 0) {
typedef int (*gnutls_cipher_setkey_func) (void *ctx, const void *key, size_t keysize);
/* old style ciphers */
typedef int (*gnutls_cipher_setiv_func) (void *ctx, const void *iv, size_t ivsize);
+typedef int (*gnutls_cipher_getiv_func) (void *ctx, void *iv, size_t ivsize);
typedef int (*gnutls_cipher_encrypt_func) (void *ctx, const void *plain, size_t plainsize,
void *encr, size_t encrsize);
typedef int (*gnutls_cipher_decrypt_func) (void *ctx, const void *encr, size_t encrsize,
_gnutls_dh_generate_key;
_gnutls_ecdh_generate_key;
_gnutls_ecdh_compute_key;
+ _gnutls_cipher_get_iv;
} GNUTLS_3_4;
GNUTLS_PRIVATE_3_4 {
return 0;
}
+static int
+wrap_nettle_cipher_getiv(void *_ctx, void *iv, size_t iv_size)
+{
+ struct nettle_cipher_ctx *ctx = _ctx;
+
+ if (iv_size < ctx->iv_size)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ memcpy(iv, ctx->iv, ctx->iv_size);
+
+ return (int) ctx->iv_size;
+}
+
static int
wrap_nettle_cipher_decrypt(void *_ctx, const void *encr, size_t encr_size,
void *plain, size_t plain_size)
.init = wrap_nettle_cipher_init,
.exists = wrap_nettle_cipher_exists,
.setiv = wrap_nettle_cipher_setiv,
+ .getiv = wrap_nettle_cipher_getiv,
.setkey = wrap_nettle_cipher_setkey,
.encrypt = wrap_nettle_cipher_encrypt,
.decrypt = wrap_nettle_cipher_decrypt,