aboutsummaryrefslogtreecommitdiffstats
path: root/ext/openssl/ossl_cipher.c
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2016-08-26 17:22:22 +0900
committerKazuki Yamaguchi <k@rhe.jp>2016-08-26 17:22:22 +0900
commitbc83a57b4acd4b4ae77a284c2c4383e8c9cdb94a (patch)
tree4bcd65f3645f11d94ab749aa75e574eff8252e08 /ext/openssl/ossl_cipher.c
parent0bcd6499a8a3233a1bbbf1ba87a019673ec888f2 (diff)
parent6bc097049b4581a90ad59986fce57141b7e571f3 (diff)
downloadruby-openssl-bc83a57b4acd4b4ae77a284c2c4383e8c9cdb94a.tar.gz
Merge branch 'topic/cipher-auth-tag-len'
* topic/cipher-auth-tag-len: cipher: add Cipher#auth_tag_len=
Diffstat (limited to 'ext/openssl/ossl_cipher.c')
-rw-r--r--ext/openssl/ossl_cipher.c48
1 files changed, 45 insertions, 3 deletions
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index c23105ab..f1f3459e 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -36,6 +36,7 @@
*/
VALUE cCipher;
VALUE eCipherError;
+static ID id_auth_tag_len;
static VALUE ossl_cipher_alloc(VALUE klass);
static void ossl_cipher_free(void *ptr);
@@ -577,8 +578,9 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
* then set on the decryption cipher to authenticate the contents of the
* ciphertext against changes. If the optional integer parameter +tag_len+ is
* given, the returned tag will be +tag_len+ bytes long. If the parameter is
- * omitted, the maximum length of 16 bytes will be returned. For maximum
- * security, the default of 16 bytes should be chosen.
+ * omitted, the default length of 16 bytes or the length previously set by
+ * #auth_tag_len= will be used. For maximum security, the longest possible
+ * should be chosen.
*
* The tag may only be retrieved after calling Cipher#final.
*/
@@ -589,7 +591,10 @@ ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
EVP_CIPHER_CTX *ctx;
int tag_len = 16;
- if (rb_scan_args(argc, argv, "01", &vtag_len) == 1)
+ rb_scan_args(argc, argv, "01", &vtag_len);
+ if (NIL_P(vtag_len))
+ vtag_len = rb_attr_get(self, id_auth_tag_len);
+ if (!NIL_P(vtag_len))
tag_len = NUM2INT(vtag_len);
GetCipher(self, ctx);
@@ -615,6 +620,9 @@ ossl_cipher_get_auth_tag(int argc, VALUE *argv, VALUE self)
* decrypting any of the ciphertext. After all decryption is
* performed, the tag is verified automatically in the call to
* Cipher#final.
+ *
+ * For OCB mode, the tag length must be supplied with #auth_tag_len=
+ * beforehand.
*/
static VALUE
ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
@@ -639,6 +647,36 @@ ossl_cipher_set_auth_tag(VALUE self, VALUE vtag)
/*
* call-seq:
+ * cipher.auth_tag_len = Integer -> Integer
+ *
+ * Sets the length of the authentication tag to be generated or to be given for
+ * AEAD ciphers that requires it as in input parameter. Note that not all AEAD
+ * ciphers support this method.
+ *
+ * In OCB mode, the length must be supplied both when encrypting and when
+ * decrypting, and must be before specifying an IV.
+ */
+static VALUE
+ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
+{
+ int tag_len = NUM2INT(vlen);
+ EVP_CIPHER_CTX *ctx;
+
+ GetCipher(self, ctx);
+ if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER))
+ ossl_raise(eCipherError, "AEAD not supported by this cipher");
+
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL))
+ ossl_raise(eCipherError, "unable to set authentication tag length");
+
+ /* for #auth_tag */
+ rb_ivar_set(self, id_auth_tag_len, INT2NUM(tag_len));
+
+ return vlen;
+}
+
+/*
+ * call-seq:
* cipher.authenticated? -> boolean
*
* Indicated whether this Cipher instance uses an Authenticated Encryption
@@ -687,6 +725,7 @@ ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
#define ossl_cipher_set_auth_data rb_f_notimplement
#define ossl_cipher_get_auth_tag rb_f_notimplement
#define ossl_cipher_set_auth_tag rb_f_notimplement
+#define ossl_cipher_set_auth_tag_len rb_f_notimplement
#define ossl_cipher_is_authenticated rb_f_notimplement
#define ossl_cipher_set_iv_length rb_f_notimplement
#endif
@@ -1032,6 +1071,7 @@ Init_ossl_cipher(void)
rb_define_method(cCipher, "auth_data=", ossl_cipher_set_auth_data, 1);
rb_define_method(cCipher, "auth_tag=", ossl_cipher_set_auth_tag, 1);
rb_define_method(cCipher, "auth_tag", ossl_cipher_get_auth_tag, -1);
+ rb_define_method(cCipher, "auth_tag_len=", ossl_cipher_set_auth_tag_len, 1);
rb_define_method(cCipher, "authenticated?", ossl_cipher_is_authenticated, 0);
rb_define_method(cCipher, "key_len=", ossl_cipher_set_key_length, 1);
rb_define_method(cCipher, "key_len", ossl_cipher_key_length, 0);
@@ -1040,4 +1080,6 @@ Init_ossl_cipher(void)
rb_define_method(cCipher, "iv_len", ossl_cipher_iv_length, 0);
rb_define_method(cCipher, "block_size", ossl_cipher_block_size, 0);
rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1);
+
+ id_auth_tag_len = rb_intern_const("auth_tag_len");
}