openssl/crypto/rsa/rsa_oaep.c
Rich Salz 474e469bbd OPENSSL_NO_xxx cleanup: SHA
Remove support for SHA0 and DSS0 (they were broken), and remove
the ability to attempt to build without SHA (it didn't work).
For simplicity, remove the option of not building various SHA algorithms;
you could argue that SHA_224/256/384/512 should be kept, since they're
like crypto algorithms, but I decided to go the other way.
So these options are gone:
	GENUINE_DSA         OPENSSL_NO_SHA0
	OPENSSL_NO_SHA      OPENSSL_NO_SHA1
	OPENSSL_NO_SHA224   OPENSSL_NO_SHA256
	OPENSSL_NO_SHA384   OPENSSL_NO_SHA512

Reviewed-by: Richard Levitte <levitte@openssl.org>
2015-01-27 12:34:45 -05:00

280 lines
8.7 KiB
C

/* crypto/rsa/rsa_oaep.c */
/*
* Written by Ulf Moeller. This software is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
*/
/* EME-OAEP as defined in RFC 2437 (PKCS #1 v2.0) */
/*
* See Victor Shoup, "OAEP reconsidered," Nov. 2000, <URL:
* http://www.shoup.net/papers/oaep.ps.Z> for problems with the security
* proof for the original OAEP scheme, which EME-OAEP is based on. A new
* proof can be found in E. Fujisaki, T. Okamoto, D. Pointcheval, J. Stern,
* "RSA-OEAP is Still Alive!", Dec. 2000, <URL:
* http://eprint.iacr.org/2000/061/>. The new proof has stronger requirements
* for the underlying permutation: "partial-one-wayness" instead of
* one-wayness. For the RSA function, this is an equivalent notion.
*/
#include "constant_time_locl.h"
#include <stdio.h>
#include "cryptlib.h"
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen,
const unsigned char *from, int flen,
const unsigned char *param, int plen)
{
return RSA_padding_add_PKCS1_OAEP_mgf1(to, tlen, from, flen,
param, plen, NULL, NULL);
}
int RSA_padding_add_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
const unsigned char *from, int flen,
const unsigned char *param, int plen,
const EVP_MD *md, const EVP_MD *mgf1md)
{
int i, emlen = tlen - 1;
unsigned char *db, *seed;
unsigned char *dbmask, seedmask[EVP_MAX_MD_SIZE];
int mdlen;
if (md == NULL)
md = EVP_sha1();
if (mgf1md == NULL)
mgf1md = md;
mdlen = EVP_MD_size(md);
if (flen > emlen - 2 * mdlen - 1) {
RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP_MGF1,
RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
return 0;
}
if (emlen < 2 * mdlen + 1) {
RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP_MGF1,
RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
}
to[0] = 0;
seed = to + 1;
db = to + mdlen + 1;
if (!EVP_Digest((void *)param, plen, db, NULL, md, NULL))
return 0;
memset(db + mdlen, 0, emlen - flen - 2 * mdlen - 1);
db[emlen - flen - mdlen - 1] = 0x01;
memcpy(db + emlen - flen - mdlen, from, (unsigned int)flen);
if (RAND_bytes(seed, mdlen) <= 0)
return 0;
#ifdef PKCS_TESTVECT
memcpy(seed,
"\xaa\xfd\x12\xf6\x59\xca\xe6\x34\x89\xb4\x79\xe5\x07\x6d\xde\xc2\xf0\x6c\xb5\x8f",
20);
#endif
dbmask = OPENSSL_malloc(emlen - mdlen);
if (dbmask == NULL) {
RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP_MGF1, ERR_R_MALLOC_FAILURE);
return 0;
}
if (PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md) < 0)
return 0;
for (i = 0; i < emlen - mdlen; i++)
db[i] ^= dbmask[i];
if (PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md) < 0)
return 0;
for (i = 0; i < mdlen; i++)
seed[i] ^= seedmask[i];
OPENSSL_free(dbmask);
return 1;
}
int RSA_padding_check_PKCS1_OAEP(unsigned char *to, int tlen,
const unsigned char *from, int flen, int num,
const unsigned char *param, int plen)
{
return RSA_padding_check_PKCS1_OAEP_mgf1(to, tlen, from, flen, num,
param, plen, NULL, NULL);
}
int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
const unsigned char *from, int flen,
int num, const unsigned char *param,
int plen, const EVP_MD *md,
const EVP_MD *mgf1md)
{
int i, dblen, mlen = -1, one_index = 0, msg_index;
unsigned int good, found_one_byte;
const unsigned char *maskedseed, *maskeddb;
/*
* |em| is the encoded message, zero-padded to exactly |num| bytes: em =
* Y || maskedSeed || maskedDB
*/
unsigned char *db = NULL, *em = NULL, seed[EVP_MAX_MD_SIZE],
phash[EVP_MAX_MD_SIZE];
int mdlen;
if (md == NULL)
md = EVP_sha1();
if (mgf1md == NULL)
mgf1md = md;
mdlen = EVP_MD_size(md);
if (tlen <= 0 || flen <= 0)
return -1;
/*
* |num| is the length of the modulus; |flen| is the length of the
* encoded message. Therefore, for any |from| that was obtained by
* decrypting a ciphertext, we must have |flen| <= |num|. Similarly,
* num < 2 * mdlen + 2 must hold for the modulus irrespective of
* the ciphertext, see PKCS #1 v2.2, section 7.1.2.
* This does not leak any side-channel information.
*/
if (num < flen || num < 2 * mdlen + 2)
goto decoding_err;
dblen = num - mdlen - 1;
db = OPENSSL_malloc(dblen);
em = OPENSSL_malloc(num);
if (db == NULL || em == NULL) {
RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, ERR_R_MALLOC_FAILURE);
goto cleanup;
}
/*
* Always do this zero-padding copy (even when num == flen) to avoid
* leaking that information. The copy still leaks some side-channel
* information, but it's impossible to have a fixed memory access
* pattern since we can't read out of the bounds of |from|.
*
* TODO(emilia): Consider porting BN_bn2bin_padded from BoringSSL.
*/
memset(em, 0, num);
memcpy(em + num - flen, from, flen);
/*
* The first byte must be zero, however we must not leak if this is
* true. See James H. Manger, "A Chosen Ciphertext Attack on RSA
* Optimal Asymmetric Encryption Padding (OAEP) [...]", CRYPTO 2001).
*/
good = constant_time_is_zero(em[0]);
maskedseed = em + 1;
maskeddb = em + 1 + mdlen;
if (PKCS1_MGF1(seed, mdlen, maskeddb, dblen, mgf1md))
goto cleanup;
for (i = 0; i < mdlen; i++)
seed[i] ^= maskedseed[i];
if (PKCS1_MGF1(db, dblen, seed, mdlen, mgf1md))
goto cleanup;
for (i = 0; i < dblen; i++)
db[i] ^= maskeddb[i];
if (!EVP_Digest((void *)param, plen, phash, NULL, md, NULL))
goto cleanup;
good &= constant_time_is_zero(CRYPTO_memcmp(db, phash, mdlen));
found_one_byte = 0;
for (i = mdlen; i < dblen; i++) {
/*
* Padding consists of a number of 0-bytes, followed by a 1.
*/
unsigned int equals1 = constant_time_eq(db[i], 1);
unsigned int equals0 = constant_time_is_zero(db[i]);
one_index = constant_time_select_int(~found_one_byte & equals1,
i, one_index);
found_one_byte |= equals1;
good &= (found_one_byte | equals0);
}
good &= found_one_byte;
/*
* At this point |good| is zero unless the plaintext was valid,
* so plaintext-awareness ensures timing side-channels are no longer a
* concern.
*/
if (!good)
goto decoding_err;
msg_index = one_index + 1;
mlen = dblen - msg_index;
if (tlen < mlen) {
RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, RSA_R_DATA_TOO_LARGE);
mlen = -1;
} else {
memcpy(to, db + msg_index, mlen);
goto cleanup;
}
decoding_err:
/*
* To avoid chosen ciphertext attacks, the error message should not
* reveal which kind of decoding error happened.
*/
RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1,
RSA_R_OAEP_DECODING_ERROR);
cleanup:
if (db != NULL)
OPENSSL_free(db);
if (em != NULL)
OPENSSL_free(em);
return mlen;
}
int PKCS1_MGF1(unsigned char *mask, long len,
const unsigned char *seed, long seedlen, const EVP_MD *dgst)
{
long i, outlen = 0;
unsigned char cnt[4];
EVP_MD_CTX c;
unsigned char md[EVP_MAX_MD_SIZE];
int mdlen;
int rv = -1;
EVP_MD_CTX_init(&c);
mdlen = M_EVP_MD_size(dgst);
if (mdlen < 0)
goto err;
for (i = 0; outlen < len; i++) {
cnt[0] = (unsigned char)((i >> 24) & 255);
cnt[1] = (unsigned char)((i >> 16) & 255);
cnt[2] = (unsigned char)((i >> 8)) & 255;
cnt[3] = (unsigned char)(i & 255);
if (!EVP_DigestInit_ex(&c, dgst, NULL)
|| !EVP_DigestUpdate(&c, seed, seedlen)
|| !EVP_DigestUpdate(&c, cnt, 4))
goto err;
if (outlen + mdlen <= len) {
if (!EVP_DigestFinal_ex(&c, mask + outlen, NULL))
goto err;
outlen += mdlen;
} else {
if (!EVP_DigestFinal_ex(&c, md, NULL))
goto err;
memcpy(mask + outlen, md, len - outlen);
outlen = len;
}
}
rv = 0;
err:
EVP_MD_CTX_cleanup(&c);
return rv;
}