sl@0: /* crypto/rsa/rsa_oaep.c */ sl@0: /* Written by Ulf Moeller. This software is distributed on an "AS IS" sl@0: basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. */ sl@0: sl@0: /* EME-OAEP as defined in RFC 2437 (PKCS #1 v2.0) */ sl@0: sl@0: /* See Victor Shoup, "OAEP reconsidered," Nov. 2000, sl@0: * sl@0: * for problems with the security proof for the sl@0: * original OAEP scheme, which EME-OAEP is based on. sl@0: * sl@0: * A new proof can be found in E. Fujisaki, T. Okamoto, sl@0: * D. Pointcheval, J. Stern, "RSA-OEAP is Still Alive!", sl@0: * Dec. 2000, . sl@0: * The new proof has stronger requirements for the sl@0: * underlying permutation: "partial-one-wayness" instead sl@0: * of one-wayness. For the RSA function, this is sl@0: * an equivalent notion. sl@0: */ sl@0: sl@0: sl@0: #if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA1) sl@0: #include sl@0: #include "cryptlib.h" sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: EXPORT_C int MGF1(unsigned char *mask, long len, sl@0: const unsigned char *seed, long seedlen); sl@0: sl@0: EXPORT_C int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen, sl@0: const unsigned char *from, int flen, sl@0: const unsigned char *param, int plen) sl@0: { sl@0: int i, emlen = tlen - 1; sl@0: unsigned char *db, *seed; sl@0: unsigned char *dbmask, seedmask[SHA_DIGEST_LENGTH]; sl@0: sl@0: if (flen > emlen - 2 * SHA_DIGEST_LENGTH - 1) sl@0: { sl@0: RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, sl@0: RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); sl@0: return 0; sl@0: } sl@0: sl@0: if (emlen < 2 * SHA_DIGEST_LENGTH + 1) sl@0: { sl@0: RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, RSA_R_KEY_SIZE_TOO_SMALL); sl@0: return 0; sl@0: } sl@0: sl@0: dbmask = OPENSSL_malloc(emlen - SHA_DIGEST_LENGTH); sl@0: if (dbmask == NULL) sl@0: { sl@0: RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, ERR_R_MALLOC_FAILURE); sl@0: return 0; sl@0: } sl@0: sl@0: to[0] = 0; sl@0: seed = to + 1; sl@0: db = to + SHA_DIGEST_LENGTH + 1; sl@0: sl@0: EVP_Digest((void *)param, plen, db, NULL, EVP_sha1(), NULL); sl@0: memset(db + SHA_DIGEST_LENGTH, 0, sl@0: emlen - flen - 2 * SHA_DIGEST_LENGTH - 1); sl@0: db[emlen - flen - SHA_DIGEST_LENGTH - 1] = 0x01; sl@0: memcpy(db + emlen - flen - SHA_DIGEST_LENGTH, from, (unsigned int) flen); sl@0: if (RAND_bytes(seed, SHA_DIGEST_LENGTH) <= 0) sl@0: return 0; sl@0: #ifdef PKCS_TESTVECT sl@0: memcpy(seed, sl@0: "\xaa\xfd\x12\xf6\x59\xca\xe6\x34\x89\xb4\x79\xe5\x07\x6d\xde\xc2\xf0\x6c\xb5\x8f", sl@0: 20); sl@0: #endif sl@0: sl@0: MGF1(dbmask, emlen - SHA_DIGEST_LENGTH, seed, SHA_DIGEST_LENGTH); sl@0: for (i = 0; i < emlen - SHA_DIGEST_LENGTH; i++) sl@0: db[i] ^= dbmask[i]; sl@0: sl@0: MGF1(seedmask, SHA_DIGEST_LENGTH, db, emlen - SHA_DIGEST_LENGTH); sl@0: for (i = 0; i < SHA_DIGEST_LENGTH; i++) sl@0: seed[i] ^= seedmask[i]; sl@0: sl@0: OPENSSL_free(dbmask); sl@0: return 1; sl@0: } sl@0: sl@0: EXPORT_C int RSA_padding_check_PKCS1_OAEP(unsigned char *to, int tlen, sl@0: const unsigned char *from, int flen, int num, sl@0: const unsigned char *param, int plen) sl@0: { sl@0: int i, dblen, mlen = -1; sl@0: const unsigned char *maskeddb; sl@0: int lzero; sl@0: unsigned char *db = NULL, seed[SHA_DIGEST_LENGTH], phash[SHA_DIGEST_LENGTH]; sl@0: int bad = 0; sl@0: sl@0: if (--num < 2 * SHA_DIGEST_LENGTH + 1) sl@0: /* 'num' is the length of the modulus, i.e. does not depend on the sl@0: * particular ciphertext. */ sl@0: goto decoding_err; sl@0: sl@0: lzero = num - flen; sl@0: if (lzero < 0) sl@0: { sl@0: /* lzero == -1 */ sl@0: sl@0: /* signalling this error immediately after detection might allow sl@0: * for side-channel attacks (e.g. timing if 'plen' is huge sl@0: * -- cf. James H. Manger, "A Chosen Ciphertext Attack on RSA Optimal sl@0: * Asymmetric Encryption Padding (OAEP) [...]", CRYPTO 2001), sl@0: * so we use a 'bad' flag */ sl@0: bad = 1; sl@0: lzero = 0; sl@0: } sl@0: maskeddb = from - lzero + SHA_DIGEST_LENGTH; sl@0: sl@0: dblen = num - SHA_DIGEST_LENGTH; sl@0: db = OPENSSL_malloc(dblen); sl@0: if (db == NULL) sl@0: { sl@0: RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP, ERR_R_MALLOC_FAILURE); sl@0: return -1; sl@0: } sl@0: sl@0: MGF1(seed, SHA_DIGEST_LENGTH, maskeddb, dblen); sl@0: for (i = lzero; i < SHA_DIGEST_LENGTH; i++) sl@0: seed[i] ^= from[i - lzero]; sl@0: sl@0: MGF1(db, dblen, seed, SHA_DIGEST_LENGTH); sl@0: for (i = 0; i < dblen; i++) sl@0: db[i] ^= maskeddb[i]; sl@0: sl@0: EVP_Digest((void *)param, plen, phash, NULL, EVP_sha1(), NULL); sl@0: sl@0: if (memcmp(db, phash, SHA_DIGEST_LENGTH) != 0 || bad) sl@0: goto decoding_err; sl@0: else sl@0: { sl@0: for (i = SHA_DIGEST_LENGTH; i < dblen; i++) sl@0: if (db[i] != 0x00) sl@0: break; sl@0: if (db[i] != 0x01 || i++ >= dblen) sl@0: goto decoding_err; sl@0: else sl@0: { sl@0: /* everything looks OK */ sl@0: sl@0: mlen = dblen - i; sl@0: if (tlen < mlen) sl@0: { sl@0: RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP, RSA_R_DATA_TOO_LARGE); sl@0: mlen = -1; sl@0: } sl@0: else sl@0: memcpy(to, db + i, mlen); sl@0: } sl@0: } sl@0: OPENSSL_free(db); sl@0: return mlen; sl@0: sl@0: decoding_err: sl@0: /* to avoid chosen ciphertext attacks, the error message should not reveal sl@0: * which kind of decoding error happened */ sl@0: RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP, RSA_R_OAEP_DECODING_ERROR); sl@0: if (db != NULL) OPENSSL_free(db); sl@0: return -1; sl@0: } sl@0: sl@0: EXPORT_C int PKCS1_MGF1(unsigned char *mask, long len, sl@0: const unsigned char *seed, long seedlen, const EVP_MD *dgst) sl@0: { sl@0: long i, outlen = 0; sl@0: unsigned char cnt[4]; sl@0: EVP_MD_CTX c; sl@0: unsigned char md[EVP_MAX_MD_SIZE]; sl@0: int mdlen; sl@0: sl@0: EVP_MD_CTX_init(&c); sl@0: mdlen = EVP_MD_size(dgst); sl@0: for (i = 0; outlen < len; i++) sl@0: { sl@0: cnt[0] = (unsigned char)((i >> 24) & 255); sl@0: cnt[1] = (unsigned char)((i >> 16) & 255); sl@0: cnt[2] = (unsigned char)((i >> 8)) & 255; sl@0: cnt[3] = (unsigned char)(i & 255); sl@0: EVP_DigestInit_ex(&c,dgst, NULL); sl@0: EVP_DigestUpdate(&c, seed, seedlen); sl@0: EVP_DigestUpdate(&c, cnt, 4); sl@0: if (outlen + mdlen <= len) sl@0: { sl@0: EVP_DigestFinal_ex(&c, mask + outlen, NULL); sl@0: outlen += mdlen; sl@0: } sl@0: else sl@0: { sl@0: EVP_DigestFinal_ex(&c, md, NULL); sl@0: memcpy(mask + outlen, md, len - outlen); sl@0: outlen = len; sl@0: } sl@0: } sl@0: EVP_MD_CTX_cleanup(&c); sl@0: return 0; sl@0: } sl@0: sl@0: EXPORT_C int MGF1(unsigned char *mask, long len, const unsigned char *seed, long seedlen) sl@0: { sl@0: return PKCS1_MGF1(mask, len, seed, seedlen, EVP_sha1()); sl@0: } sl@0: #endif