Feature #6980 » openssl_aead_ciphers.patch
ext/openssl/ossl_cipher.c | ||
---|---|---|
/*
|
||
* call-seq:
|
||
* cipher.verify -> string
|
||
*
|
||
* Verifies the decrypted ciphertext against the tag set prior to
|
||
* decryption using the ciphertext and optional associated
|
||
* authentication data. Returns an empty string if the ciphertext was
|
||
* authenticated successfully, otherwise raises an
|
||
* OpenSSL::Cipher::CipherError.
|
||
*
|
||
* Only call this method after setting the authentication tag
|
||
* appropriate for your cipher mode and passing the entire contents
|
||
* of the ciphertext into the cipher, and before calling
|
||
* Cipher#final.
|
||
*/
|
||
static VALUE
|
||
ossl_cipher_verify(VALUE self)
|
||
{
|
||
EVP_CIPHER_CTX *ctx;
|
||
int out_len = 0;
|
||
GetCipher(self, ctx);
|
||
if (!EVP_CipherUpdate(ctx, NULL, &out_len, NULL, 0))
|
||
ossl_raise(eCipherError, "ciphertext failed to authenticate");
|
||
return rb_str_new(0, 0);
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* cipher.name -> string
|
||
*
|
||
* Returns the name of the cipher which may differ slightly from the original
|
||
... | ... | |
return iv;
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* cipher.aad = string -> string
|
||
*
|
||
* Sets the cipher's additional authenticated data. This field may be
|
||
* set optionally before using AEAD cipher modes such as GCM or
|
||
* CCM. The contents of this field should be non-sensitive
|
||
* data which will be added to the ciphertext to generate the
|
||
* authentication tag which validates the contents of the ciphertext.
|
||
*
|
||
* The AAD must be set prior to encryption or decryption. Only call
|
||
* this method after calling Cipher#encrypt when encrypting, and
|
||
* after Cipher#decrypt and Cipher#gcm_tag= when decrypting.
|
||
*/
|
||
static VALUE
|
||
ossl_cipher_set_aad(VALUE self, VALUE data)
|
||
{
|
||
EVP_CIPHER_CTX *ctx;
|
||
unsigned char *in = NULL;
|
||
int in_len = 0;
|
||
int out_len = 0;
|
||
StringValue(data);
|
||
in = (unsigned char *) RSTRING_PTR(data);
|
||
in_len = RSTRING_LENINT(data);
|
||
GetCipher(self, ctx);
|
||
if (!EVP_CipherUpdate(ctx, NULL, &out_len, in, in_len))
|
||
ossl_raise(eCipherError, "couldn't set additional authenticated data");
|
||
return self;
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* cipher.gcm_tag -> string
|
||
*
|
||
* Gets the authentication tag generated by GCM cipher modes. This
|
||
* tag may be stored along with the ciphertext, then set on the
|
||
* decryption cipher to authenticate the contents of the ciphertext
|
||
* against changes.
|
||
*
|
||
* The tag may only be retrieved after calling Cipher#final.
|
||
*/
|
||
static VALUE
|
||
ossl_cipher_get_gcm_tag(VALUE self)
|
||
{
|
||
EVP_CIPHER_CTX *ctx;
|
||
VALUE tag;
|
||
// GCM tags are 16 bytes in OpenSSL
|
||
tag = rb_str_new(NULL, 16);
|
||
GetCipher(self, ctx);
|
||
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, (unsigned char *)RSTRING_PTR(tag)))
|
||
ossl_raise(eCipherError, "Cipher#finish must be called before getting the tag");
|
||
return tag;
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* cipher.gcm_tag = string -> string
|
||
*
|
||
* Sets the authentication tag to verify the contents of the
|
||
* ciphertext. The GCM tag must be set after calling Cipher#decrypt
|
||
* but before decrypting any of the ciphertext. After all decryption
|
||
* is performed, the tag can be verified by calling Cipher#verify.
|
||
*/
|
||
static VALUE
|
||
ossl_cipher_set_gcm_tag(VALUE self, VALUE data)
|
||
{
|
||
EVP_CIPHER_CTX *ctx;
|
||
unsigned char *in = NULL;
|
||
int in_len = 0;
|
||
StringValue(data);
|
||
in = (unsigned char *) RSTRING_PTR(data);
|
||
in_len = RSTRING_LENINT(data);
|
||
GetCipher(self, ctx);
|
||
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, in_len, in))
|
||
ossl_raise(eCipherError, "unable to set GCM tag");
|
||
return data;
|
||
}
|
||
/*
|
||
* call-seq:
|
||
... | ... | |
rb_define_method(cCipher, "pkcs5_keyivgen", ossl_cipher_pkcs5_keyivgen, -1);
|
||
rb_define_method(cCipher, "update", ossl_cipher_update, -1);
|
||
rb_define_method(cCipher, "final", ossl_cipher_final, 0);
|
||
rb_define_method(cCipher, "verify", ossl_cipher_verify, 0);
|
||
rb_define_method(cCipher, "name", ossl_cipher_name, 0);
|
||
rb_define_method(cCipher, "key=", ossl_cipher_set_key, 1);
|
||
rb_define_method(cCipher, "aad=", ossl_cipher_set_aad, 1);
|
||
rb_define_method(cCipher, "gcm_tag=", ossl_cipher_set_gcm_tag, 1);
|
||
rb_define_method(cCipher, "gcm_tag", ossl_cipher_get_gcm_tag, 0);
|
||
rb_define_method(cCipher, "key_len=", ossl_cipher_set_key_length, 1);
|
||
rb_define_method(cCipher, "key_len", ossl_cipher_key_length, 0);
|
||
rb_define_method(cCipher, "iv=", ossl_cipher_set_iv, 1);
|
test/openssl/test_cipher.rb | ||
---|---|---|
end
|
||
end
|
||
end
|
||
if OpenSSL::OPENSSL_VERSION_NUMBER > 0x1000103f
|
||
def test_aes_gcm
|
||
pt = File.read(__FILE__)
|
||
c1 = OpenSSL::Cipher.new('aes-256-gcm')
|
||
c2 = OpenSSL::Cipher.new('aes-256-gcm')
|
||
c3 = OpenSSL::Cipher.new('aes-256-gcm')
|
||
c1.encrypt
|
||
c1.pkcs5_keyivgen('passwd')
|
||
c1.aad = 'aad'
|
||
ct = c1.update(pt) + c1.final
|
||
tag = c1.gcm_tag
|
||
c2.decrypt
|
||
c2.pkcs5_keyivgen('passwd')
|
||
c2.gcm_tag = tag
|
||
c2.aad = 'aad'
|
||
assert_equal(pt, c2.update(ct) + c2.verify + c2.final)
|
||
c3.decrypt
|
||
c3.pkcs5_keyivgen('passwd')
|
||
c3.gcm_tag = tag[0..-2] << tag[-1].succ
|
||
c3.aad = 'aad'
|
||
assert_raise OpenSSL::Cipher::CipherError do
|
||
c3.update(ct) + c3.verify + c3.final
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|
- « Previous
- 1
- 2
- Next »