From c9ba00d73300e9d5d84e1d8f39f6abee1a2e379c Mon Sep 17 00:00:00 2001 From: Pengfei Zhao Date: Sun, 7 Aug 2022 22:12:33 +0800 Subject: [PATCH 1/3] Fix insecure prng (#3) * Add RDSEED and RDRAND instruction check in compile time * Use RDSEED/RDRAND to produce random big number --- CMakeLists.txt | 17 ++++++++++++++ ipcl/CMakeLists.txt | 1 + ipcl/common.cpp | 42 +++++++++++++++++++++++++++++++++++ ipcl/include/ipcl/common.hpp | 9 ++++++++ ipcl/include/ipcl/pub_key.hpp | 14 ------------ ipcl/keygen.cpp | 24 +++++--------------- ipcl/pub_key.cpp | 38 +++---------------------------- 7 files changed, 77 insertions(+), 68 deletions(-) create mode 100644 ipcl/common.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bdaf00..92aab59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,6 +115,23 @@ else() endif() endif() +# check whether cpu support rdseed or rdrand instruction +set(CPU_RDSEED_FLAG "rdseed") +execute_process(COMMAND lscpu COMMAND grep ${CPU_RDSEED_FLAG} OUTPUT_VARIABLE CPU_ENABLE_RDSEED) +if("${CPU_ENABLE_RDSEED}" STREQUAL "") + set(CPU_RDRAND_FLAG "rdrand") + execute_process(COMMAND lscpu COMMAND grep ${CPU_RDRAND_FLAG} OUTPUT_VARIABLE CPU_ENABLE_RDRAND) + if("${CPU_ENABLE_RDRAND}" STREQUAL "") + message(WARNING "CPU doesn't support RDSEED and RDRAND instruction, using random generator will cause errors.") + else () + message(STATUS "Support RDRAND instruction: True") + add_compile_definitions(IPCL_RNG_INSTR_RDRAND) + endif() +else() + message(STATUS "Support RDSEED instruction: True") + add_compile_definitions(IPCL_RNG_INSTR_RDSEED) +endif() + # find package for OpenSSL and Threads set(OPENSSL_USE_STATIC_LIBS TRUE) find_package(Threads REQUIRED) diff --git a/ipcl/CMakeLists.txt b/ipcl/CMakeLists.txt index ef76656..b1388b2 100644 --- a/ipcl/CMakeLists.txt +++ b/ipcl/CMakeLists.txt @@ -10,6 +10,7 @@ set(IPCL_SRCS pri_key.cpp plaintext.cpp ciphertext.cpp util.cpp + common.cpp ) diff --git a/ipcl/common.cpp b/ipcl/common.cpp new file mode 100644 index 0000000..b4813d0 --- /dev/null +++ b/ipcl/common.cpp @@ -0,0 +1,42 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "ipcl/common.hpp" + +#include + +#include "ipcl/util.hpp" + +namespace ipcl { + +BigNumber getRandomBN(int bit_len) { + IppStatus stat; + int bn_buf_size; + + int bn_len = BITSIZE_WORD(bit_len); + stat = ippsBigNumGetSize(bn_len, &bn_buf_size); + ERROR_CHECK(stat == ippStsNoErr, + "getRandomBN: get IppsBigNumState context error."); + + IppsBigNumState* pBN = + reinterpret_cast(alloca(bn_buf_size)); + ERROR_CHECK(pBN != nullptr, "getRandomBN: big number alloca error"); + + stat = ippsBigNumInit(bn_len, pBN); + ERROR_CHECK(stat == ippStsNoErr, + "getRandomBN: init big number context error."); + +#ifdef IPCL_RNG_INSTR_RDSEED + ippsTRNGenRDSEED_BN(pBN, bit_len, NULL); +#elif defined(IPCL_RNG_INSTR_RDRAND) + ippsPRNGenRDRAND_BN(pBN, bit_len, NULL); +#else + ERROR_CHECK( + false, + "getRandomBN: CPU doest NOT support RDSEED and RDRAND instruction"); +#endif + + return BigNumber{pBN}; +} + +} // namespace ipcl diff --git a/ipcl/include/ipcl/common.hpp b/ipcl/include/ipcl/common.hpp index f954026..e83d476 100644 --- a/ipcl/include/ipcl/common.hpp +++ b/ipcl/include/ipcl/common.hpp @@ -4,9 +4,18 @@ #ifndef IPCL_INCLUDE_IPCL_COMMON_HPP_ #define IPCL_INCLUDE_IPCL_COMMON_HPP_ +#include "ipcl/bignum.h" + namespace ipcl { constexpr int IPCL_CRYPTO_MB_SIZE = 8; +/** + * Get random value + * @param[in] length bit length + * @return the random value of type BigNumber + */ +BigNumber getRandomBN(int length); + } // namespace ipcl #endif // IPCL_INCLUDE_IPCL_COMMON_HPP_ diff --git a/ipcl/include/ipcl/pub_key.hpp b/ipcl/include/ipcl/pub_key.hpp index 6938e40..1b28d19 100644 --- a/ipcl/include/ipcl/pub_key.hpp +++ b/ipcl/include/ipcl/pub_key.hpp @@ -128,13 +128,6 @@ class PublicKey { std::vector m_r; bool m_testv; - /** - * Get random value - * @param[in] size size of random - * @return addr of random of type Ipp32u vector - */ - std::vector randIpp32u(int size) const; - /** * Big number vector multi buffer encryption * @param[in] pt plaintext of BigNumber vector type @@ -144,13 +137,6 @@ class PublicKey { std::vector raw_encrypt(const std::vector& pt, bool make_secure = true) const; - /** - * Get random value - * @param[in] length bit length - * @return the random value of type BigNumber - */ - BigNumber getRandom(int length) const; - void applyDjnObfuscator(std::vector& obfuscator) const; void applyNormalObfuscator(std::vector& obfuscator) const; diff --git a/ipcl/keygen.cpp b/ipcl/keygen.cpp index efbf1d6..789bfea 100644 --- a/ipcl/keygen.cpp +++ b/ipcl/keygen.cpp @@ -3,8 +3,6 @@ #include "ipcl/keygen.hpp" -#include -#include #include #include "ipcl/util.hpp" @@ -12,14 +10,7 @@ namespace ipcl { constexpr int N_BIT_SIZE_MAX = 2048; -constexpr int N_BIT_SIZE_MIN = 16; - -static void rand32u(std::vector& addr) { - std::random_device dev; - std::mt19937 rng(dev()); - std::uniform_int_distribution dist(0, UINT_MAX); - for (auto& x : addr) x = (dist(rng) << 16) + dist(rng); -} +constexpr int N_BIT_SIZE_MIN = 200; BigNumber getPrimeBN(int maxBitSize) { int PrimeSize; @@ -27,19 +18,14 @@ BigNumber getPrimeBN(int maxBitSize) { auto primeGen = std::vector(PrimeSize); ippsPrimeInit(maxBitSize, reinterpret_cast(primeGen.data())); - // define Pseudo Random Generator (default settings) + // default seed bit size constexpr int seedBitSize = 160; - constexpr int seedSize = BITSIZE_WORD(seedBitSize); + BigNumber seed = getRandomBN(seedBitSize); - ippsPRNGGetSize(&PrimeSize); auto rand = std::vector(PrimeSize); ippsPRNGInit(seedBitSize, reinterpret_cast(rand.data())); - auto seed = std::vector(seedSize); - rand32u(seed); - BigNumber bseed(seed.data(), seedSize, IppsBigNumPOS); - - ippsPRNGSetSeed(BN(bseed), reinterpret_cast(rand.data())); + ippsPRNGSetSeed(seed, reinterpret_cast(rand.data())); // generate maxBit prime BigNumber pBN(0, maxBitSize / 8); @@ -111,7 +97,7 @@ keyPair generateKeypair(int64_t n_length, bool enable_DJN) { "generateKeyPair: modulus size in bits should belong to either 1Kb, 2Kb, " "3Kb or 4Kb range only, key size exceed the range!!!"); ERROR_CHECK((n_length >= N_BIT_SIZE_MIN) && (n_length % 4 == 0), - "generateKeyPair: key size should >=16, and divisible by 4"); + "generateKeyPair: key size should >=200, and divisible by 4"); BigNumber ref_dist = getPrimeDistance(n_length); diff --git a/ipcl/pub_key.cpp b/ipcl/pub_key.cpp index d19c915..0968691 100644 --- a/ipcl/pub_key.cpp +++ b/ipcl/pub_key.cpp @@ -35,44 +35,12 @@ PublicKey::PublicKey(const BigNumber& n, int bits, bool enableDJN_) if (enableDJN_) this->enableDJN(); // sets m_enable_DJN } -// array of 32-bit random, using rand() from stdlib -std::vector PublicKey::randIpp32u(int size) const { - std::vector addr(size); - // TODO(skmono): check if copy of m_init_seed is needed for const - unsigned int init_seed = m_init_seed; - for (auto& a : addr) a = (rand_r(&init_seed) << 16) + rand_r(&init_seed); - return addr; -} - -// length is arbitrary -BigNumber PublicKey::getRandom(int bit_len) const { - IppStatus stat; - int bn_buf_size; - - // define length Big Numbers - int bn_len = BITSIZE_WORD(bit_len); - stat = ippsBigNumGetSize(bn_len, &bn_buf_size); - ERROR_CHECK(stat == ippStsNoErr, - "getRandom: get IppsBigNumState context error."); - - IppsBigNumState* pBN = - reinterpret_cast(alloca(bn_buf_size)); - ERROR_CHECK(pBN != nullptr, "getRandom: big number alloca error"); - - stat = ippsBigNumInit(bn_len, pBN); - ERROR_CHECK(stat == ippStsNoErr, "getRandom: init big number context error."); - - ippsPRNGenRDRAND_BN(pBN, bit_len, NULL); - - return BigNumber{pBN}; -} - void PublicKey::enableDJN() { BigNumber gcd; BigNumber rmod; do { int rand_bit = m_n.BitSize(); - BigNumber rand = getRandom(rand_bit + 128); + BigNumber rand = getRandomBN(rand_bit + 128); rmod = rand % m_n; gcd = rand.gcd(m_n); } while (gcd.compare(1)); @@ -96,7 +64,7 @@ void PublicKey::applyDjnObfuscator(std::vector& obfuscator) const { r = m_r; } else { for (auto& r_ : r) { - r_ = getRandom(m_randbits); + r_ = getRandomBN(m_randbits); } } obfuscator = ipcl::ippModExp(base, r, sq); @@ -113,7 +81,7 @@ void PublicKey::applyNormalObfuscator( r = m_r; } else { for (int i = 0; i < obf_size; i++) { - r[i] = getRandom(m_bits); + r[i] = getRandomBN(m_bits); r[i] = r[i] % (m_n - 1) + 1; } } From 6d5e1be1833fb04dec332ff665496eddfaba1a85 Mon Sep 17 00:00:00 2001 From: Sejun Kim Date: Mon, 8 Aug 2022 22:21:34 +0900 Subject: [PATCH 2/3] Add RNG support for non-RDRAND, non-RDSEED systems (#5) - Uses IPP-Crypto pseudo random number generator if none of those instructions are supported - Minor typo fixes --- README.md | 2 +- ipcl/common.cpp | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9ef5c92..114d654 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Intel Paillier Cryptosystem Library -Intel Paillier Cryptosystem Library is an open-source library which provides accelerated performance of a partial homomorphic encryption (HE), named Paillier cryptosystem, by utilizing IntelĀ® [Integrated Performance Primitives Cryptography](https://github.com/intel/ipp-crypto) technologies on Intel CPUs supporting the AVX512IFMA instructions. The library is written in modern standard C++ and provides the essential API for the Paillier cryptosystem scheme. Intel Paillier Cryptosystem Library is certified for ISO compliance. +Intel Paillier Cryptosystem Library is an open-source library which provides accelerated performance of a partial homomorphic encryption (HE), named Paillier cryptosystem, by utilizing IntelĀ® [Integrated Performance Primitives Cryptography](https://github.com/intel/ipp-crypto) technologies on Intel CPUs supporting the AVX512IFMA instructions. The library is written in modern standard C++ and provides the essential API for the Paillier cryptosystem scheme. Intel Paillier Cryptosystem Library is certified for ISO compliance. ## Contents - [Intel Paillier Cryptosystem Library](#intel-paillier-cryptosystem-library) diff --git a/ipcl/common.cpp b/ipcl/common.cpp index b4813d0..b8e6274 100644 --- a/ipcl/common.cpp +++ b/ipcl/common.cpp @@ -31,9 +31,7 @@ BigNumber getRandomBN(int bit_len) { #elif defined(IPCL_RNG_INSTR_RDRAND) ippsPRNGenRDRAND_BN(pBN, bit_len, NULL); #else - ERROR_CHECK( - false, - "getRandomBN: CPU doest NOT support RDSEED and RDRAND instruction"); + ippsPRNGen_BN(pBN, bit_len, NULL); #endif return BigNumber{pBN}; From 2eb799b4cdf1916904197fc52c7a100b757bed78 Mon Sep 17 00:00:00 2001 From: Pengfei Zhao Date: Mon, 22 Aug 2022 13:54:06 +0800 Subject: [PATCH 3/3] Removing seed setup and replacing rng function for PrimeGen_BN (#8) - getPrimeBN: remove seed setup - ippsPrimeGen_BN: add support to TRNGen_RDSEED and PRNGen_RDRAND --- ipcl/common.cpp | 34 +++++++++++++++++++++-------- ipcl/include/ipcl/common.hpp | 26 +++++++++++++++++++--- ipcl/keygen.cpp | 42 +++++++++++++++++------------------- 3 files changed, 68 insertions(+), 34 deletions(-) diff --git a/ipcl/common.cpp b/ipcl/common.cpp index b8e6274..90209eb 100644 --- a/ipcl/common.cpp +++ b/ipcl/common.cpp @@ -9,11 +9,31 @@ namespace ipcl { -BigNumber getRandomBN(int bit_len) { +IppStatus ippGenRandom(Ipp32u* rand, int bits, void* ctx) { +#ifdef IPCL_RNG_INSTR_RDSEED + return ippsTRNGenRDSEED(rand, bits, ctx); +#elif defined(IPCL_RNG_INSTR_RDRAND) + return ippsPRNGenRDRAND(rand, bits, ctx); +#else + return ippsPRNGen(rand, bits, ctx); +#endif +} + +IppStatus ippGenRandomBN(IppsBigNumState* rand, int bits, void* ctx) { +#ifdef IPCL_RNG_INSTR_RDSEED + return ippsTRNGenRDSEED_BN(rand, bits, ctx); +#elif defined(IPCL_RNG_INSTR_RDRAND) + return ippsPRNGenRDRAND_BN(rand, bits, ctx); +#else + return ippsPRNGen_BN(rand, bits, ctx); +#endif +} + +BigNumber getRandomBN(int bits) { IppStatus stat; int bn_buf_size; - int bn_len = BITSIZE_WORD(bit_len); + int bn_len = BITSIZE_WORD(bits); stat = ippsBigNumGetSize(bn_len, &bn_buf_size); ERROR_CHECK(stat == ippStsNoErr, "getRandomBN: get IppsBigNumState context error."); @@ -26,13 +46,9 @@ BigNumber getRandomBN(int bit_len) { ERROR_CHECK(stat == ippStsNoErr, "getRandomBN: init big number context error."); -#ifdef IPCL_RNG_INSTR_RDSEED - ippsTRNGenRDSEED_BN(pBN, bit_len, NULL); -#elif defined(IPCL_RNG_INSTR_RDRAND) - ippsPRNGenRDRAND_BN(pBN, bit_len, NULL); -#else - ippsPRNGen_BN(pBN, bit_len, NULL); -#endif + stat = ippGenRandomBN(pBN, bits, NULL); + ERROR_CHECK(stat == ippStsNoErr, + "getRandomBN: generate random big number error."); return BigNumber{pBN}; } diff --git a/ipcl/include/ipcl/common.hpp b/ipcl/include/ipcl/common.hpp index e83d476..e15d44e 100644 --- a/ipcl/include/ipcl/common.hpp +++ b/ipcl/include/ipcl/common.hpp @@ -10,12 +10,32 @@ namespace ipcl { constexpr int IPCL_CRYPTO_MB_SIZE = 8; +/** + * Random generator wrapper.Generates a random unsigned Big Number of the + * specified bit length + * @param[in] rand Pointer to the output unsigned integer big number + * @param[in] bits The number of generated bits + * @param[in] ctx Pointer to the IppsPRNGState context. + * @return Error code + */ +IppStatus ippGenRandom(Ipp32u* rand, int bits, void* ctx); + +/** + * Random generator wrapper.Generates a random positive Big Number of the + * specified bit length + * @param[in] rand Pointer to the output Big Number + * @param[in] bits The number of generated bits + * @param[in] ctx Pointer to the IppsPRNGState context. + * @return Error code + */ +IppStatus ippGenRandomBN(IppsBigNumState* rand, int bits, void* ctx); + /** * Get random value - * @param[in] length bit length - * @return the random value of type BigNumber + * @param[in] bits The number of Big Number bits + * @return The random value of type Big Number */ -BigNumber getRandomBN(int length); +BigNumber getRandomBN(int bits); } // namespace ipcl #endif // IPCL_INCLUDE_IPCL_COMMON_HPP_ diff --git a/ipcl/keygen.cpp b/ipcl/keygen.cpp index 789bfea..290e502 100644 --- a/ipcl/keygen.cpp +++ b/ipcl/keygen.cpp @@ -12,31 +12,29 @@ namespace ipcl { constexpr int N_BIT_SIZE_MAX = 2048; constexpr int N_BIT_SIZE_MIN = 200; -BigNumber getPrimeBN(int maxBitSize) { - int PrimeSize; - ippsPrimeGetSize(maxBitSize, &PrimeSize); - auto primeGen = std::vector(PrimeSize); - ippsPrimeInit(maxBitSize, reinterpret_cast(primeGen.data())); - - // default seed bit size - constexpr int seedBitSize = 160; - BigNumber seed = getRandomBN(seedBitSize); - - auto rand = std::vector(PrimeSize); - ippsPRNGInit(seedBitSize, reinterpret_cast(rand.data())); - - ippsPRNGSetSeed(seed, reinterpret_cast(rand.data())); - - // generate maxBit prime - BigNumber pBN(0, maxBitSize / 8); +BigNumber getPrimeBN(int max_bits) { + int prime_size; + ippsPrimeGetSize(max_bits, &prime_size); + auto prime_ctx = std::vector(prime_size); + ippsPrimeInit(max_bits, reinterpret_cast(prime_ctx.data())); + +#if defined(IPCL_RNG_INSTR_RDSEED) || defined(IPCL_RNG_INSTR_RDRAND) + bool rand_param = NULL; +#else + auto buff = std::vector(prime_size); + auto rand_param = buff.data(); + ippsPRNGInit(160, reinterpret_cast(rand_param)); +#endif + + BigNumber prime_bn(0, max_bits / 8); while (ippStsNoErr != - ippsPrimeGen_BN(pBN, maxBitSize, 10, - reinterpret_cast(primeGen.data()), - ippsPRNGen, - reinterpret_cast(rand.data()))) { + ippsPrimeGen_BN(prime_bn, max_bits, 10, + reinterpret_cast(prime_ctx.data()), + ippGenRandom, + reinterpret_cast(rand_param))) { } - return pBN; + return prime_bn; } static BigNumber getPrimeDistance(int64_t key_size) {