Add RSA OAEP and PSS padding
Functions added: * `encrypt_oaep(self, plaintext, hash_type, mgf, label)` * `decrypt_oaep(self, ciphertext, hash_type, mgf, label)` * `sign_pss(self, plaintext, hash_type, mgf)` * `verify_pss(self, plaintext, signature, hash_type, mgf)` Constants added: * MGF1SHA224 * MGF1SHA256 * MGF1SHA384 * MGF1SHA512 * HASH_TYPE_NONE * HASH_TYPE_MD2 * HASH_TYPE_MD4 * HASH_TYPE_MD5 * HASH_TYPE_SHA * HASH_TYPE_SHA224 * HASH_TYPE_SHA256 * HASH_TYPE_SHA384 * HASH_TYPE_SHA512 * HASH_TYPE_MD5_SHA * HASH_TYPE_SHA3_224 * HASH_TYPE_SHA3_256 * HASH_TYPE_SHA3_384 * HASH_TYPE_SHA3_512 * HASH_TYPE_BLAKE2B * HASH_TYPE_BLAKE2Spull/36/head
parent
726c37e9e7
commit
863e6836a9
|
@ -1,6 +1,6 @@
|
|||
# test_hashes.py
|
||||
# test_aesgcmstream.py
|
||||
#
|
||||
# Copyright (C) 2006-2022 wolfSSL Inc.
|
||||
# Copyright (C) 2022 wolfSSL Inc.
|
||||
#
|
||||
# This file is part of wolfSSL. (formerly known as CyaSSL)
|
||||
#
|
||||
|
|
|
@ -39,7 +39,7 @@ if _lib.CHACHA_ENABLED:
|
|||
from wolfcrypt.ciphers import ChaCha
|
||||
|
||||
if _lib.RSA_ENABLED:
|
||||
from wolfcrypt.ciphers import (RsaPrivate, RsaPublic)
|
||||
from wolfcrypt.ciphers import (RsaPrivate, RsaPublic, HASH_TYPE_SHA256, MGF1SHA256, HASH_TYPE_SHA, MGF1SHA1)
|
||||
|
||||
if _lib.ECC_ENABLED:
|
||||
from wolfcrypt.ciphers import (EccPrivate, EccPublic)
|
||||
|
@ -382,6 +382,23 @@ if _lib.RSA_ENABLED:
|
|||
assert 1024 / 8 == len(ciphertext) == rsa_private.output_size
|
||||
assert plaintext == rsa_private.decrypt(ciphertext)
|
||||
|
||||
def test_rsa_encrypt_decrypt_pad_oaep(rsa_private, rsa_public):
|
||||
plaintext = t2b("Everyone gets Friday off.")
|
||||
|
||||
# normal usage, encrypt with public, decrypt with private
|
||||
ciphertext = rsa_public.encrypt_oaep(plaintext, HASH_TYPE_SHA, MGF1SHA1, "")
|
||||
|
||||
assert 1024 / 8 == len(ciphertext) == rsa_public.output_size
|
||||
assert plaintext == rsa_private.decrypt_oaep(ciphertext, HASH_TYPE_SHA, MGF1SHA1, "")
|
||||
|
||||
# private object holds both private and public info, so it can also encrypt
|
||||
# using the known public key.
|
||||
ciphertext = rsa_private.encrypt_oaep(plaintext, HASH_TYPE_SHA, MGF1SHA1, "")
|
||||
|
||||
assert 1024 / 8 == len(ciphertext) == rsa_private.output_size
|
||||
assert plaintext == rsa_private.decrypt_oaep(ciphertext, HASH_TYPE_SHA, MGF1SHA1, "")
|
||||
|
||||
|
||||
def test_rsa_pkcs8_encrypt_decrypt(rsa_private_pkcs8, rsa_public):
|
||||
plaintext = t2b("Everyone gets Friday off.")
|
||||
|
||||
|
@ -415,6 +432,22 @@ if _lib.RSA_ENABLED:
|
|||
assert 1024 / 8 == len(signature) == rsa_private.output_size
|
||||
assert plaintext == rsa_private.verify(signature)
|
||||
|
||||
def test_rsa_pss_sign_verify(rsa_private, rsa_public):
|
||||
plaintext = t2b("Everyone gets Friday off yippee.")
|
||||
|
||||
# normal usage, sign with private, verify with public
|
||||
signature = rsa_private.sign_pss(plaintext, HASH_TYPE_SHA256, MGF1SHA256)
|
||||
|
||||
assert 1024 / 8 == len(signature) == rsa_private.output_size
|
||||
assert 0 == rsa_public.verify_pss(plaintext, signature, HASH_TYPE_SHA256, MGF1SHA256)
|
||||
|
||||
# private object holds both private and public info, so it can also verify
|
||||
# using the known public key.
|
||||
signature = rsa_private.sign_pss(plaintext, HASH_TYPE_SHA256, MGF1SHA256)
|
||||
|
||||
assert 1024 / 8 == len(signature) == rsa_private.output_size
|
||||
assert 0 == rsa_private.verify_pss(plaintext, signature, HASH_TYPE_SHA256, MGF1SHA256)
|
||||
|
||||
def test_rsa_sign_verify_pem(rsa_private_pem, rsa_public_pem):
|
||||
plaintext = t2b("Everyone gets Friday off.")
|
||||
|
||||
|
|
|
@ -381,12 +381,22 @@ if RSA_ENABLED:
|
|||
RsaKey* key);
|
||||
int wc_RsaPublicEncrypt(const byte*, word32, byte*, word32,
|
||||
RsaKey*, WC_RNG*);
|
||||
|
||||
int wc_RsaPublicEncrypt_ex(const byte* in, word32 inLen, byte* out,
|
||||
word32 outLen, RsaKey* key, WC_RNG* rng, int type,
|
||||
enum wc_HashType hash, int mgf, byte* label, word32 labelSz);
|
||||
int wc_RsaPrivateDecrypt_ex(const byte* in, word32 inLen,
|
||||
byte* out, word32 outLen, RsaKey* key, int type,
|
||||
enum wc_HashType hash, int mgf, byte* label, word32 labelSz);
|
||||
int wc_RsaPSS_Sign(const byte* in, word32 inLen, byte* out, word32 outLen,
|
||||
enum wc_HashType hash, int mgf, RsaKey* key, WC_RNG* rng);
|
||||
int wc_RsaPSS_Verify(byte* in, word32 inLen, byte* out, word32 outLen,
|
||||
enum wc_HashType hash, int mgf, RsaKey* key);
|
||||
int wc_RsaPSS_CheckPadding(const byte* in, word32 inSz, byte* sig,
|
||||
word32 sigSz, enum wc_HashType hashType);
|
||||
int wc_RsaSSL_Sign(const byte*, word32, byte*, word32, RsaKey*, WC_RNG*);
|
||||
int wc_RsaSSL_Verify(const byte*, word32, byte*, word32, RsaKey*);
|
||||
"""
|
||||
|
||||
|
||||
if RSA_BLINDING_ENABLED:
|
||||
_cdef += """
|
||||
int wc_RsaSetRNG(RsaKey* key, WC_RNG* rng);
|
||||
|
|
|
@ -153,6 +153,7 @@ def make_flags(prefix):
|
|||
flags.append("-DWOLFSSL_SHA224=no")
|
||||
flags.append("-DWOLFSSL_POLY1305=no")
|
||||
flags.append("-DWOLFSSL_RSA=yes")
|
||||
flags.append("-DWOLFSSL_RSA_PSS=yes")
|
||||
flags.append("-DWOLFSSL_ECC=yes")
|
||||
flags.append("-DWOLFSSL_ED25519=yes")
|
||||
flags.append("-DWOLFSSL_ED448=yes")
|
||||
|
@ -205,6 +206,7 @@ def make_flags(prefix):
|
|||
|
||||
# asymmetric ciphers
|
||||
flags.append("--enable-rsa")
|
||||
flags.append("--enable-rsapss")
|
||||
flags.append("--enable-ecc")
|
||||
flags.append("--enable-ed25519")
|
||||
flags.append("--enable-ed448")
|
||||
|
|
|
@ -82,6 +82,39 @@ ECC_BRAINPOOLP320R1 = 25
|
|||
ECC_BRAINPOOLP384R1 = 26
|
||||
ECC_BRAINPOOLP512R1 = 27
|
||||
|
||||
RSA_PKCSV15_PAD = 0
|
||||
RSA_OAEP_PAD = 1
|
||||
RSA_PSS_PAD = 2
|
||||
RSA_NO_PSA = 3
|
||||
|
||||
MGF1NONE = 0
|
||||
MGF1SHA1 = 26
|
||||
MGF1SHA224 = 4
|
||||
MGF1SHA256 = 1
|
||||
MGF1SHA384 = 2
|
||||
MGF1SHA512 = 3
|
||||
|
||||
BLOCK_TYPE_1 = 1
|
||||
BLOCK_TYPE_2 = 2
|
||||
|
||||
HASH_TYPE_NONE = 0
|
||||
HASH_TYPE_MD2 = 1
|
||||
HASH_TYPE_MD4 = 2
|
||||
HASH_TYPE_MD5 = 3
|
||||
HASH_TYPE_SHA = 4
|
||||
HASH_TYPE_SHA224 = 5
|
||||
HASH_TYPE_SHA256 = 6
|
||||
HASH_TYPE_SHA384 = 7
|
||||
HASH_TYPE_SHA512 = 8
|
||||
HASH_TYPE_MD5_SHA = 9
|
||||
HASH_TYPE_SHA3_224 = 10
|
||||
HASH_TYPE_SHA3_256 = 11
|
||||
HASH_TYPE_SHA3_384 = 12
|
||||
HASH_TYPE_SHA3_512 = 13
|
||||
HASH_TYPE_BLAKE2B = 14
|
||||
HASH_TYPE_BLAKE2S = 15
|
||||
|
||||
|
||||
|
||||
class _Cipher(object):
|
||||
"""
|
||||
|
@ -473,6 +506,23 @@ if _lib.RSA_ENABLED:
|
|||
|
||||
return _ffi.buffer(ciphertext)[:]
|
||||
|
||||
def encrypt_oaep(self, plaintext, hash_type, mgf, label):
|
||||
plaintext = t2b(plaintext)
|
||||
label = t2b(label)
|
||||
ciphertext = _ffi.new("byte[%d]" % self.output_size)
|
||||
|
||||
ret = _lib.wc_RsaPublicEncrypt_ex(plaintext, len(plaintext),
|
||||
ciphertext, self.output_size,
|
||||
self.native_object,
|
||||
self._random.native_object,
|
||||
RSA_OAEP_PAD, hash_type, mgf,
|
||||
label, len(label))
|
||||
|
||||
if ret != self.output_size: # pragma: no cover
|
||||
raise WolfCryptError("Encryption error (%d)" % ret)
|
||||
|
||||
return _ffi.buffer(ciphertext)[:]
|
||||
|
||||
def verify(self, signature):
|
||||
"""
|
||||
Verifies **signature**, using the public key data in the
|
||||
|
@ -494,6 +544,32 @@ if _lib.RSA_ENABLED:
|
|||
|
||||
return _ffi.buffer(plaintext, ret)[:]
|
||||
|
||||
def verify_pss(self, plaintext, signature, hash_type, mgf):
|
||||
"""
|
||||
Verifies **signature**, using the public key data in the
|
||||
object. The signature's length must be equal to:
|
||||
|
||||
**self.output_size**
|
||||
|
||||
Returns a string containing the plaintext.
|
||||
"""
|
||||
plaintext = t2b(plaintext)
|
||||
signature = t2b(signature)
|
||||
verify = _ffi.new("byte[%d]" % self.output_size)
|
||||
|
||||
ret = _lib.wc_RsaPSS_Verify(signature, len(signature),
|
||||
verify, self.output_size,
|
||||
hash_type, mgf,
|
||||
self.native_object)
|
||||
|
||||
if ret < 0: # pragma: no cover
|
||||
raise WolfCryptError("Verify error (%d)" % ret)
|
||||
ret = _lib.wc_RsaPSS_CheckPadding(plaintext, len(plaintext),
|
||||
verify, ret, hash_type)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
class RsaPrivate(RsaPublic):
|
||||
if _lib.KEYGEN_ENABLED:
|
||||
|
@ -597,6 +673,28 @@ if _lib.RSA_ENABLED:
|
|||
|
||||
return _ffi.buffer(plaintext, ret)[:]
|
||||
|
||||
def decrypt_oaep(self, ciphertext, hash_type, mgf, label):
|
||||
"""
|
||||
Decrypts **ciphertext**, using the private key data in the
|
||||
object. The ciphertext's length must be equal to:
|
||||
|
||||
**self.output_size**
|
||||
|
||||
Returns a string containing the plaintext.
|
||||
"""
|
||||
ciphertext = t2b(ciphertext)
|
||||
label = t2b(label)
|
||||
plaintext = _ffi.new("byte[%d]" % self.output_size)
|
||||
ret = _lib.wc_RsaPrivateDecrypt_ex(ciphertext, len(ciphertext),
|
||||
plaintext, self.output_size,
|
||||
self.native_object, RSA_OAEP_PAD,
|
||||
hash_type, mgf, label, len(label))
|
||||
|
||||
if ret < 0: # pragma: no cover
|
||||
raise WolfCryptError("Decryption error (%d)" % ret)
|
||||
|
||||
return _ffi.buffer(plaintext, ret)[:]
|
||||
|
||||
def sign(self, plaintext):
|
||||
"""
|
||||
Signs **plaintext**, using the private key data in the object.
|
||||
|
@ -619,6 +717,29 @@ if _lib.RSA_ENABLED:
|
|||
|
||||
return _ffi.buffer(signature, self.output_size)[:]
|
||||
|
||||
def sign_pss(self, plaintext, hash_type, mgf):
|
||||
"""
|
||||
Signs **plaintext**, using the private key data in the object.
|
||||
The plaintext's length must not be greater than:
|
||||
|
||||
**self.output_size - self.RSA_MIN_PAD_SIZE**
|
||||
|
||||
Returns a string containing the signature.
|
||||
"""
|
||||
plaintext = t2b(plaintext)
|
||||
signature = _ffi.new("byte[%d]" % self.output_size)
|
||||
|
||||
ret = _lib.wc_RsaPSS_Sign(plaintext, len(plaintext),
|
||||
signature, self.output_size,
|
||||
hash_type, mgf,
|
||||
self.native_object,
|
||||
self._random.native_object)
|
||||
|
||||
if ret != self.output_size: # pragma: no cover
|
||||
raise WolfCryptError("Signature error (%d)" % ret)
|
||||
|
||||
return _ffi.buffer(signature, self.output_size)[:]
|
||||
|
||||
|
||||
if _lib.ECC_ENABLED:
|
||||
class _Ecc(object): # pylint: disable=too-few-public-methods
|
||||
|
|
Loading…
Reference in New Issue