parent
8d81492f88
commit
64d02e3a18
|
|
@ -253,6 +253,8 @@ safer.cpp
|
||||||
safer.h
|
safer.h
|
||||||
salsa.cpp
|
salsa.cpp
|
||||||
salsa.h
|
salsa.h
|
||||||
|
scrypt.cpp
|
||||||
|
scrypt.h
|
||||||
seal.cpp
|
seal.cpp
|
||||||
seal.h
|
seal.h
|
||||||
secblock.h
|
secblock.h
|
||||||
|
|
|
||||||
|
|
@ -278,6 +278,7 @@
|
||||||
<ClCompile Include="rw.cpp" />
|
<ClCompile Include="rw.cpp" />
|
||||||
<ClCompile Include="safer.cpp" />
|
<ClCompile Include="safer.cpp" />
|
||||||
<ClCompile Include="salsa.cpp" />
|
<ClCompile Include="salsa.cpp" />
|
||||||
|
<ClCompile Include="scrypt.cpp" />
|
||||||
<ClCompile Include="seal.cpp" />
|
<ClCompile Include="seal.cpp" />
|
||||||
<ClCompile Include="seed.cpp" />
|
<ClCompile Include="seed.cpp" />
|
||||||
<ClCompile Include="serpent.cpp" />
|
<ClCompile Include="serpent.cpp" />
|
||||||
|
|
@ -468,6 +469,7 @@
|
||||||
<ClInclude Include="rw.h" />
|
<ClInclude Include="rw.h" />
|
||||||
<ClInclude Include="safer.h" />
|
<ClInclude Include="safer.h" />
|
||||||
<ClInclude Include="salsa.h" />
|
<ClInclude Include="salsa.h" />
|
||||||
|
<ClInclude Include="scrypt.h" />
|
||||||
<ClInclude Include="seal.h" />
|
<ClInclude Include="seal.h" />
|
||||||
<ClInclude Include="secblock.h" />
|
<ClInclude Include="secblock.h" />
|
||||||
<ClInclude Include="seckey.h" />
|
<ClInclude Include="seckey.h" />
|
||||||
|
|
@ -515,4 +517,4 @@
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
|
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -329,6 +329,9 @@
|
||||||
<ClCompile Include="salsa.cpp">
|
<ClCompile Include="salsa.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="scrypt.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="seal.cpp">
|
<ClCompile Include="seal.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
@ -801,6 +804,9 @@
|
||||||
<ClInclude Include="salsa.h">
|
<ClInclude Include="salsa.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="scrypt.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="seal.h">
|
<ClInclude Include="seal.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
@ -939,4 +945,4 @@
|
||||||
<Filter>Miscellaneous</Filter>
|
<Filter>Miscellaneous</Filter>
|
||||||
</CustomBuild>
|
</CustomBuild>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include "cryptlib.h"
|
#include "cryptlib.h"
|
||||||
#include "hrtimer.h"
|
#include "hrtimer.h"
|
||||||
#include "integer.h"
|
#include "integer.h"
|
||||||
|
#include "argnames.h"
|
||||||
#include "hmac.h"
|
#include "hmac.h"
|
||||||
|
|
||||||
NAMESPACE_BEGIN(CryptoPP)
|
NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,312 @@
|
||||||
|
// scrypt.cpp - written and placed in public domain by Jeffrey Walton.
|
||||||
|
// Based on reference source code by Colin Percival and Simon Josefsson.
|
||||||
|
|
||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
#include "scrypt.h"
|
||||||
|
#include "argnames.h"
|
||||||
|
#include "pwdbased.h"
|
||||||
|
#include "stdcpp.h"
|
||||||
|
#include "salsa.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "sha.h"
|
||||||
|
|
||||||
|
#ifdef _OPENMP
|
||||||
|
# include <omp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
ANONYMOUS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
using CryptoPP::rotlConstant;
|
||||||
|
using CryptoPP::AlignedSecByteBlock;
|
||||||
|
using CryptoPP::LITTLE_ENDIAN_ORDER;
|
||||||
|
using CryptoPP::ConditionalByteReverse;
|
||||||
|
|
||||||
|
static inline void LE32ENC(uint8_t* out, uint32_t in)
|
||||||
|
{
|
||||||
|
uint32_t* ptr = reinterpret_cast<uint32_t*>(out);
|
||||||
|
ConditionalByteReverse(LITTLE_ENDIAN_ORDER, ptr, &in, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t LE32DEC(const uint8_t* in)
|
||||||
|
{
|
||||||
|
uint32_t res;
|
||||||
|
const uint32_t* ptr = reinterpret_cast<const uint32_t*>(in);
|
||||||
|
ConditionalByteReverse(LITTLE_ENDIAN_ORDER, &res, ptr, 4);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t LE64DEC(const uint8_t* in)
|
||||||
|
{
|
||||||
|
uint64_t res;
|
||||||
|
const uint64_t* ptr = reinterpret_cast<const uint64_t*>(in);
|
||||||
|
ConditionalByteReverse(LITTLE_ENDIAN_ORDER, &res, ptr, 8);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void BlockCopy(uint8_t * dest, uint8_t * src, size_t len)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
dest[i] = src[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void BlockXOR(uint8_t * dest, uint8_t * src, size_t len)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
dest[i] ^= src[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void PBKDF2_SHA256(uint8_t * buf, size_t dkLen,
|
||||||
|
const uint8_t * passwd, size_t passwdlen,
|
||||||
|
const uint8_t * salt, size_t saltlen, uint8_t count)
|
||||||
|
{
|
||||||
|
using CryptoPP::SHA256;
|
||||||
|
using CryptoPP::PKCS5_PBKDF2_HMAC;
|
||||||
|
|
||||||
|
PKCS5_PBKDF2_HMAC<SHA256> pbkdf;
|
||||||
|
pbkdf.DeriveKey(buf, dkLen, 0, passwd, passwdlen, salt, saltlen, count, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void Salsa20_8(uint8_t B[64])
|
||||||
|
{
|
||||||
|
uint32_t B32[16], x[16];
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
B32[i] = LE32DEC(&B[i * 4]);
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
x[i] = B32[i];
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i += 2)
|
||||||
|
{
|
||||||
|
x[ 4] ^= rotlConstant< 7>(x[ 0]+x[12]);
|
||||||
|
x[ 8] ^= rotlConstant< 9>(x[ 4]+x[ 0]);
|
||||||
|
x[12] ^= rotlConstant<13>(x[ 8]+x[ 4]);
|
||||||
|
x[ 0] ^= rotlConstant<18>(x[12]+x[ 8]);
|
||||||
|
|
||||||
|
x[ 9] ^= rotlConstant< 7>(x[ 5]+x[ 1]);
|
||||||
|
x[13] ^= rotlConstant< 9>(x[ 9]+x[ 5]);
|
||||||
|
x[ 1] ^= rotlConstant<13>(x[13]+x[ 9]);
|
||||||
|
x[ 5] ^= rotlConstant<18>(x[ 1]+x[13]);
|
||||||
|
|
||||||
|
x[14] ^= rotlConstant< 7>(x[10]+x[ 6]);
|
||||||
|
x[ 2] ^= rotlConstant< 9>(x[14]+x[10]);
|
||||||
|
x[ 6] ^= rotlConstant<13>(x[ 2]+x[14]);
|
||||||
|
x[10] ^= rotlConstant<18>(x[ 6]+x[ 2]);
|
||||||
|
|
||||||
|
x[ 3] ^= rotlConstant< 7>(x[15]+x[11]);
|
||||||
|
x[ 7] ^= rotlConstant< 9>(x[ 3]+x[15]);
|
||||||
|
x[11] ^= rotlConstant<13>(x[ 7]+x[ 3]);
|
||||||
|
x[15] ^= rotlConstant<18>(x[11]+x[ 7]);
|
||||||
|
|
||||||
|
x[ 1] ^= rotlConstant< 7>(x[ 0]+x[ 3]);
|
||||||
|
x[ 2] ^= rotlConstant< 9>(x[ 1]+x[ 0]);
|
||||||
|
x[ 3] ^= rotlConstant<13>(x[ 2]+x[ 1]);
|
||||||
|
x[ 0] ^= rotlConstant<18>(x[ 3]+x[ 2]);
|
||||||
|
|
||||||
|
x[ 6] ^= rotlConstant< 7>(x[ 5]+x[ 4]);
|
||||||
|
x[ 7] ^= rotlConstant< 9>(x[ 6]+x[ 5]);
|
||||||
|
x[ 4] ^= rotlConstant<13>(x[ 7]+x[ 6]);
|
||||||
|
x[ 5] ^= rotlConstant<18>(x[ 4]+x[ 7]);
|
||||||
|
|
||||||
|
x[11] ^= rotlConstant< 7>(x[10]+x[ 9]);
|
||||||
|
x[ 8] ^= rotlConstant< 9>(x[11]+x[10]);
|
||||||
|
x[ 9] ^= rotlConstant<13>(x[ 8]+x[11]);
|
||||||
|
x[10] ^= rotlConstant<18>(x[ 9]+x[ 8]);
|
||||||
|
|
||||||
|
x[12] ^= rotlConstant< 7>(x[15]+x[14]);
|
||||||
|
x[13] ^= rotlConstant< 9>(x[12]+x[15]);
|
||||||
|
x[14] ^= rotlConstant<13>(x[13]+x[12]);
|
||||||
|
x[15] ^= rotlConstant<18>(x[14]+x[13]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
B32[i] += x[i];
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
LE32ENC(&B[4 * i], B32[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void BlockMix(uint8_t * B, uint8_t * Y, size_t r)
|
||||||
|
{
|
||||||
|
uint8_t X[64];
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
// 1: X <-- B_{2r - 1}
|
||||||
|
BlockCopy(X, &B[(2 * r - 1) * 64], 64);
|
||||||
|
|
||||||
|
// 2: for i = 0 to 2r - 1 do
|
||||||
|
for (i = 0; i < 2 * r; i++)
|
||||||
|
{
|
||||||
|
// 3: X <-- H(X \xor B_i)
|
||||||
|
BlockXOR(X, &B[i * 64], 64);
|
||||||
|
Salsa20_8(X);
|
||||||
|
|
||||||
|
// 4: Y_i <-- X
|
||||||
|
BlockCopy(&Y[i * 64], X, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1})
|
||||||
|
for (i = 0; i < r; i++)
|
||||||
|
BlockCopy(&B[i * 64], &Y[(i * 2) * 64], 64);
|
||||||
|
for (i = 0; i < r; i++)
|
||||||
|
BlockCopy(&B[(i + r) * 64], &Y[(i * 2 + 1) * 64], 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t Integerify(uint8_t * B, size_t r)
|
||||||
|
{
|
||||||
|
uint8_t * X = &B[(2 * r - 1) * 64];
|
||||||
|
return LE64DEC(X);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void Smix(uint8_t * B, size_t r, uint64_t N, uint8_t * V, uint8_t * XY)
|
||||||
|
{
|
||||||
|
uint8_t * X = XY;
|
||||||
|
uint8_t * Y = XY+128*r;
|
||||||
|
uint64_t i, j;
|
||||||
|
|
||||||
|
// 1: X <-- B
|
||||||
|
BlockCopy(X, B, 128 * r);
|
||||||
|
|
||||||
|
// 2: for i = 0 to N - 1 do
|
||||||
|
for (i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
// 3: V_i <-- X
|
||||||
|
BlockCopy(&V[i * (128 * r)], X, 128 * r);
|
||||||
|
|
||||||
|
// 4: X <-- H(X)
|
||||||
|
BlockMix(X, Y, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6: for i = 0 to N - 1 do
|
||||||
|
for (i = 0; i < N; i++) {
|
||||||
|
// 7: j <-- Integerify(X) mod N
|
||||||
|
j = Integerify(X, r) & (N - 1);
|
||||||
|
|
||||||
|
// 8: X <-- H(X \xor V_j)
|
||||||
|
BlockXOR(X, &V[j * (128 * r)], 128 * r);
|
||||||
|
BlockMix(X, Y, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 10: B' <-- X
|
||||||
|
BlockCopy(B, X, 128 * r);
|
||||||
|
}
|
||||||
|
ANONYMOUS_NAMESPACE_END
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
||||||
|
size_t Scrypt::GetValidDerivedLength(size_t keylength) const
|
||||||
|
{
|
||||||
|
if (keylength > MaxDerivedLength())
|
||||||
|
return MaxDerivedLength();
|
||||||
|
return keylength;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scrypt::ValidateParameters(size_t derivedLen, word64 cost, word64 blockSize, word64 parallelization) const
|
||||||
|
{
|
||||||
|
// Optimizer should remove this on 64-bit platforms
|
||||||
|
if (std::numeric_limits<size_t>::max() > std::numeric_limits<uint32_t>::max())
|
||||||
|
{
|
||||||
|
const uint64_t maxLen = ((static_cast<uint64_t>(1) << 32) - 1) * 32;
|
||||||
|
if (derivedLen > maxLen) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "derivedLen " << derivedLen << " is larger than " << maxLen;
|
||||||
|
throw InvalidArgument("Scrypt: " + oss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsPowerOf2(cost) == false)
|
||||||
|
throw InvalidArgument("Scrypt: cost must be a power of 2");
|
||||||
|
|
||||||
|
const uint64_t prod = static_cast<uint64_t>(blockSize) * parallelization;
|
||||||
|
if (prod >= (1U << 30)) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "r*p " << prod << " is larger than " << (1U << 30);
|
||||||
|
throw InvalidArgument("Scrypt: " + oss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scrypt has several tests that effectively verify allocations like
|
||||||
|
// '128 * r * N' and '128 * r * p' do not overflow. They are the tests
|
||||||
|
// that set errno to ENOMEM. We can make the logic a little more clear
|
||||||
|
// using word128. At first blush the word128 may seem like overkill.
|
||||||
|
// However, this alogirthm is dominated by slow moving parts, so a
|
||||||
|
// one-time check is insignificant in the bigger picture.
|
||||||
|
#if defined(CRYPTOPP_WORD128_AVAILABLE)
|
||||||
|
const word128 maxElems = static_cast<word128>(SIZE_MAX);
|
||||||
|
bool bLimit = (maxElems >= static_cast<word128>(cost) * blockSize * 128U);
|
||||||
|
bool xyLimit = (maxElems >= static_cast<word128>(parallelization) * blockSize * 128U);
|
||||||
|
bool vLimit = (maxElems >= static_cast<word128>(blockSize) * 256U + 64U);
|
||||||
|
if (!bLimit || !xyLimit || !vLimit)
|
||||||
|
throw std::bad_alloc();
|
||||||
|
#else
|
||||||
|
const word64 maxElems = static_cast<word64>(SIZE_MAX);
|
||||||
|
bool bLimit = (blockSize < maxElems / 128U / cost);
|
||||||
|
bool xyLimit = (blockSize < maxElems / 128U / parallelization);
|
||||||
|
bool vLimit = (blockSize < (maxElems - 64U) / 256U);
|
||||||
|
|
||||||
|
if (!bLimit || !xyLimit || !vLimit)
|
||||||
|
throw std::bad_alloc();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Scrypt::DeriveKey(byte *derived, size_t derivedLen,
|
||||||
|
const byte *secret, size_t secretLen, const NameValuePairs& params) const
|
||||||
|
{
|
||||||
|
CRYPTOPP_ASSERT(secret /*&& secretLen*/);
|
||||||
|
CRYPTOPP_ASSERT(derived && derivedLen);
|
||||||
|
CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
|
||||||
|
|
||||||
|
word64 cost=0, blockSize=0, parallelization=0;
|
||||||
|
|
||||||
|
if(params.GetValue("Cost", cost) == false)
|
||||||
|
cost = defaultCost;
|
||||||
|
|
||||||
|
if(params.GetValue("BlockSize", blockSize) == false)
|
||||||
|
blockSize = defaultBlockSize;
|
||||||
|
|
||||||
|
if(params.GetValue("Parallelization", parallelization) == false)
|
||||||
|
parallelization = defaultParallelization;
|
||||||
|
|
||||||
|
ConstByteArrayParameter salt;
|
||||||
|
(void)params.GetValue("Salt", salt);
|
||||||
|
|
||||||
|
return DeriveKey(derived, derivedLen, secret, secretLen, salt.begin(), salt.size(), cost, blockSize, parallelization);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Scrypt::DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen,
|
||||||
|
const byte *salt, size_t saltLen, word64 cost, word64 blockSize, word64 parallel) const
|
||||||
|
{
|
||||||
|
CRYPTOPP_ASSERT(secret /*&& secretLen*/);
|
||||||
|
CRYPTOPP_ASSERT(derived && derivedLen);
|
||||||
|
CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
|
||||||
|
CRYPTOPP_ASSERT(IsPowerOf2(cost));
|
||||||
|
|
||||||
|
ThrowIfInvalidDerivedLength(derivedLen);
|
||||||
|
ValidateParameters(derivedLen, cost, blockSize, parallel);
|
||||||
|
|
||||||
|
AlignedSecByteBlock B(static_cast<size_t>(blockSize * parallel * 128U));
|
||||||
|
AlignedSecByteBlock XY(static_cast<size_t>(blockSize * 256U));
|
||||||
|
AlignedSecByteBlock V(static_cast<size_t>(blockSize * cost * 128U));
|
||||||
|
|
||||||
|
// 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen)
|
||||||
|
PBKDF2_SHA256(B, B.size(), secret, secretLen, salt, saltLen, 1);
|
||||||
|
|
||||||
|
// 2: for i = 0 to p - 1 do
|
||||||
|
for (unsigned int i = 0; i < parallel; i++)
|
||||||
|
{
|
||||||
|
// 3: B_i <-- MF(B_i, N)
|
||||||
|
Smix(B+static_cast<ptrdiff_t>(blockSize*i*128), static_cast<size_t>(blockSize), cost, V, XY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5: DK <-- PBKDF2(P, B, 1, dkLen)
|
||||||
|
PBKDF2_SHA256(derived, derivedLen, secret, secretLen, B, static_cast<size_t>(blockSize*parallel*128), 1);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMESPACE_END
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
// scrypt.h - written and placed in public domain by Jeffrey Walton.
|
||||||
|
// Based on reference source code by Colin Percival and Simon Josefsson.
|
||||||
|
|
||||||
|
/// \file scrypt.h
|
||||||
|
/// \brief Classes for Scrypt from RFC 7914
|
||||||
|
/// \sa <A HREF="https://www.tarsnap.com/scrypt/scrypt.pdf">Stronger Key Derivation via
|
||||||
|
/// Sequential Memory-Hard Functions</a>,
|
||||||
|
/// <A HREF="https://www.tarsnap.com/scrypt.html">The scrypt key derivation function</A>
|
||||||
|
/// and <A HREF="https://tools.ietf.org/html/rfc7914">RFC 7914, The scrypt Password-Based
|
||||||
|
/// Key Derivation Function</A>
|
||||||
|
/// \since Crypto++ 6.2
|
||||||
|
|
||||||
|
#ifndef CRYPTOPP_SCRYPT_H
|
||||||
|
#define CRYPTOPP_SCRYPT_H
|
||||||
|
|
||||||
|
#include "cryptlib.h"
|
||||||
|
#include "secblock.h"
|
||||||
|
#include "algparam.h"
|
||||||
|
|
||||||
|
NAMESPACE_BEGIN(CryptoPP)
|
||||||
|
|
||||||
|
/// \brief Scrypt key derivation function
|
||||||
|
/// \sa <A HREF="https://www.tarsnap.com/scrypt.html">The scrypt key derivation function</A>
|
||||||
|
/// and <A HREF="https://tools.ietf.org/html/rfc7914">RFC 7914, The scrypt Password-Based
|
||||||
|
/// Key Derivation Function</A>
|
||||||
|
/// \since Crypto++ 6.2
|
||||||
|
class Scrypt : public KeyDerivationFunction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Scrypt() {}
|
||||||
|
|
||||||
|
static std::string StaticAlgorithmName () {
|
||||||
|
return "scrypt";
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyDerivationFunction interface
|
||||||
|
std::string AlgorithmName() const {
|
||||||
|
return StaticAlgorithmName();
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyDerivationFunction interface
|
||||||
|
size_t MaxDerivedLength() const {
|
||||||
|
return static_cast<size_t>(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeyDerivationFunction interface
|
||||||
|
size_t GetValidDerivedLength(size_t keylength) const;
|
||||||
|
|
||||||
|
// KeyDerivationFunction interface
|
||||||
|
size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen,
|
||||||
|
const NameValuePairs& params) const;
|
||||||
|
|
||||||
|
/// \brief Derive a key from a seed
|
||||||
|
/// \param derived the derived output buffer
|
||||||
|
/// \param derivedLen the size of the derived buffer, in bytes
|
||||||
|
/// \param secret the seed input buffer
|
||||||
|
/// \param secretLen the size of the secret buffer, in bytes
|
||||||
|
/// \param salt the salt input buffer
|
||||||
|
/// \param saltLen the size of the salt buffer, in bytes
|
||||||
|
/// \param cost the CPU/memory cost factor
|
||||||
|
/// \param blockSize the block size
|
||||||
|
/// \param parallelization the parallelization factor
|
||||||
|
/// \param infoLen the size of the info buffer, in bytes
|
||||||
|
/// \returns the number of iterations performed
|
||||||
|
/// \throws InvalidDerivedLength if <tt>derivedLen</tt> is invalid for the scheme
|
||||||
|
/// \details DeriveKey() provides a standard interface to derive a key from
|
||||||
|
/// a seed and other parameters. Each class that derives from KeyDerivationFunction
|
||||||
|
/// provides an overload that accepts most parameters used by the derivation function.
|
||||||
|
/// \details The CPU/Memory <tt>cost</tt> parameter ("N" in the documents) must be
|
||||||
|
/// larger than 1, a power of 2, and less than <tt>2^(128 * r / 8)</tt>.
|
||||||
|
/// \details The parameter <tt>blockSize</tt> ("r" in the documents) specifies the block
|
||||||
|
/// size.
|
||||||
|
/// \details The <tt>parallelization</tt> parameter ("p" in the documents) is a positive
|
||||||
|
/// integer less than or equal to <tt>((2^32-1) * 32) / (128 * r)</tt>.
|
||||||
|
/// \details Crypto++ uses <tt>size_t</tt> for its size datatype, and limits are
|
||||||
|
/// based on the 32-bit version of <tt>size_t</tt>. For example, <tt>cost</tt> is
|
||||||
|
/// limited to <tt>0xffffffff</tt> instead of <tt>2^(128 * r / 8)</tt>.
|
||||||
|
/// \details Scrypt always returns 1 because it only performs 1 iteration. Other
|
||||||
|
/// derivation functions, like PBKDF's, will return more interesting values.
|
||||||
|
size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen,
|
||||||
|
const byte *salt, size_t saltLen, word64 cost=2, word64 blockSize=8, word64 parallelization=1) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum {defaultCost=2, defaultBlockSize=8, defaultParallelization=1};
|
||||||
|
|
||||||
|
// KeyDerivationFunction interface
|
||||||
|
const Algorithm & GetAlgorithm() const {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ValidateParameters(size_t derivedlen, word64 cost, word64 blockSize, word64 parallelization) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // CRYPTOPP_SCRYPT_H
|
||||||
47
test.cpp
47
test.cpp
|
|
@ -925,29 +925,30 @@ bool Validate(int alg, bool thorough, const char *seedInput)
|
||||||
case 56: result = ValidateAdler32(); break;
|
case 56: result = ValidateAdler32(); break;
|
||||||
case 57: result = ValidateMD4(); break;
|
case 57: result = ValidateMD4(); break;
|
||||||
case 58: result = ValidatePBKDF(); break;
|
case 58: result = ValidatePBKDF(); break;
|
||||||
case 59: result = ValidateESIGN(); break;
|
case 59: result = ValidateHKDF(); break;
|
||||||
case 60: result = ValidateDLIES(); break;
|
case 60: result = ValidateScrypt(); break;
|
||||||
case 61: result = ValidateBaseCode(); break;
|
case 61: result = ValidateESIGN(); break;
|
||||||
case 62: result = ValidateSHACAL2(); break;
|
case 62: result = ValidateDLIES(); break;
|
||||||
case 63: result = ValidateARIA(); break;
|
case 63: result = ValidateBaseCode(); break;
|
||||||
case 64: result = ValidateCamellia(); break;
|
case 64: result = ValidateSHACAL2(); break;
|
||||||
case 65: result = ValidateWhirlpool(); break;
|
case 65: result = ValidateARIA(); break;
|
||||||
case 66: result = ValidateTTMAC(); break;
|
case 66: result = ValidateCamellia(); break;
|
||||||
case 67: result = ValidateSalsa(); break;
|
case 67: result = ValidateWhirlpool(); break;
|
||||||
case 68: result = ValidateSosemanuk(); break;
|
case 68: result = ValidateTTMAC(); break;
|
||||||
case 69: result = ValidateVMAC(); break;
|
case 69: result = ValidateSalsa(); break;
|
||||||
case 70: result = ValidateCCM(); break;
|
case 70: result = ValidateSosemanuk(); break;
|
||||||
case 71: result = ValidateGCM(); break;
|
case 71: result = ValidateVMAC(); break;
|
||||||
case 72: result = ValidateCMAC(); break;
|
case 72: result = ValidateCCM(); break;
|
||||||
case 73: result = ValidateHKDF(); break;
|
case 73: result = ValidateGCM(); break;
|
||||||
case 74: result = ValidateSM3(); break;
|
case 74: result = ValidateCMAC(); break;
|
||||||
case 75: result = ValidateBLAKE2s(); break;
|
case 75: result = ValidateSM3(); break;
|
||||||
case 76: result = ValidateBLAKE2b(); break;
|
case 76: result = ValidateBLAKE2s(); break;
|
||||||
case 77: result = ValidatePoly1305(); break;
|
case 77: result = ValidateBLAKE2b(); break;
|
||||||
case 78: result = ValidateSipHash(); break;
|
case 78: result = ValidatePoly1305(); break;
|
||||||
case 79: result = ValidateHashDRBG(); break;
|
case 79: result = ValidateSipHash(); break;
|
||||||
case 80: result = ValidateHmacDRBG(); break;
|
case 80: result = ValidateHashDRBG(); break;
|
||||||
case 90: result = ValidateNaCl(); break;
|
case 81: result = ValidateHmacDRBG(); break;
|
||||||
|
case 82: result = ValidateNaCl(); break;
|
||||||
|
|
||||||
#if defined(CRYPTOPP_EXTENDED_VALIDATION)
|
#if defined(CRYPTOPP_EXTENDED_VALIDATION)
|
||||||
// http://github.com/weidai11/cryptopp/issues/92
|
// http://github.com/weidai11/cryptopp/issues/92
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,7 @@ bool ValidateAll(bool thorough)
|
||||||
|
|
||||||
pass=ValidatePBKDF() && pass;
|
pass=ValidatePBKDF() && pass;
|
||||||
pass=ValidateHKDF() && pass;
|
pass=ValidateHKDF() && pass;
|
||||||
|
pass=ValidateScrypt() && pass;
|
||||||
|
|
||||||
pass=ValidateDES() && pass;
|
pass=ValidateDES() && pass;
|
||||||
pass=ValidateCipherModes() && pass;
|
pass=ValidateCipherModes() && pass;
|
||||||
|
|
|
||||||
88
validat3.cpp
88
validat3.cpp
|
|
@ -28,6 +28,7 @@
|
||||||
#include "ttmac.h"
|
#include "ttmac.h"
|
||||||
#include "integer.h"
|
#include "integer.h"
|
||||||
#include "pwdbased.h"
|
#include "pwdbased.h"
|
||||||
|
#include "scrypt.h"
|
||||||
#include "filters.h"
|
#include "filters.h"
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
#include "hex.h"
|
#include "hex.h"
|
||||||
|
|
@ -671,9 +672,9 @@ bool TestHKDF(KeyDerivationFunction &kdf, const HKDF_TestTuple *testSet, unsigne
|
||||||
|
|
||||||
AlgorithmParameters params;
|
AlgorithmParameters params;
|
||||||
if (tuple.hexSalt)
|
if (tuple.hexSalt)
|
||||||
params.operator()(Name::Salt(), ConstByteArrayParameter((const byte*)&salt[0], salt.size()));
|
params(Name::Salt(), ConstByteArrayParameter((const byte*)&salt[0], salt.size()));
|
||||||
if (tuple.hexSalt)
|
if (tuple.hexSalt)
|
||||||
params.operator()("Info", ConstByteArrayParameter((const byte*)&info[0], info.size()));
|
params("Info", ConstByteArrayParameter((const byte*)&info[0], info.size()));
|
||||||
|
|
||||||
kdf.DeriveKey((byte*)&derived[0], derived.size(), (const byte*)&secret[0], secret.size(), params);
|
kdf.DeriveKey((byte*)&derived[0], derived.size(), (const byte*)&secret[0], secret.size(), params);
|
||||||
|
|
||||||
|
|
@ -700,7 +701,7 @@ bool ValidateHKDF()
|
||||||
|
|
||||||
{
|
{
|
||||||
// SHA-1 from RFC 5869, Appendix A, https://tools.ietf.org/html/rfc5869
|
// SHA-1 from RFC 5869, Appendix A, https://tools.ietf.org/html/rfc5869
|
||||||
static const HKDF_TestTuple testSet[] =
|
const HKDF_TestTuple testSet[] =
|
||||||
{
|
{
|
||||||
// Test Case #4
|
// Test Case #4
|
||||||
{"0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "085a01ea1b10f36933068b56efa5ad81 a4f14b822f5b091568a9cdd4f155fda2 c22e422478d305f3f896", 42},
|
{"0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "085a01ea1b10f36933068b56efa5ad81 a4f14b822f5b091568a9cdd4f155fda2 c22e422478d305f3f896", 42},
|
||||||
|
|
@ -720,7 +721,7 @@ bool ValidateHKDF()
|
||||||
|
|
||||||
{
|
{
|
||||||
// SHA-256 from RFC 5869, Appendix A, https://tools.ietf.org/html/rfc5869
|
// SHA-256 from RFC 5869, Appendix A, https://tools.ietf.org/html/rfc5869
|
||||||
static const HKDF_TestTuple testSet[] =
|
const HKDF_TestTuple testSet[] =
|
||||||
{
|
{
|
||||||
// Test Case #1
|
// Test Case #1
|
||||||
{"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "3cb25f25faacd57a90434f64d0362f2a 2d2d0a90cf1a5a4c5db02d56ecc4c5bf 34007208d5b887185865", 42},
|
{"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "3cb25f25faacd57a90434f64d0362f2a 2d2d0a90cf1a5a4c5db02d56ecc4c5bf 34007208d5b887185865", 42},
|
||||||
|
|
@ -738,7 +739,7 @@ bool ValidateHKDF()
|
||||||
|
|
||||||
{
|
{
|
||||||
// SHA-512, Crypto++ generated, based on RFC 5869, https://tools.ietf.org/html/rfc5869
|
// SHA-512, Crypto++ generated, based on RFC 5869, https://tools.ietf.org/html/rfc5869
|
||||||
static const HKDF_TestTuple testSet[] =
|
const HKDF_TestTuple testSet[] =
|
||||||
{
|
{
|
||||||
// Test Case #0
|
// Test Case #0
|
||||||
{"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "832390086CDA71FB47625BB5CEB168E4 C8E26A1A16ED34D9FC7FE92C14815793 38DA362CB8D9F925D7CB", 42},
|
{"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "832390086CDA71FB47625BB5CEB168E4 C8E26A1A16ED34D9FC7FE92C14815793 38DA362CB8D9F925D7CB", 42},
|
||||||
|
|
@ -758,7 +759,7 @@ bool ValidateHKDF()
|
||||||
|
|
||||||
{
|
{
|
||||||
// Whirlpool, Crypto++ generated, based on RFC 5869, https://tools.ietf.org/html/rfc5869
|
// Whirlpool, Crypto++ generated, based on RFC 5869, https://tools.ietf.org/html/rfc5869
|
||||||
static const HKDF_TestTuple testSet[] =
|
const HKDF_TestTuple testSet[] =
|
||||||
{
|
{
|
||||||
// Test Case #0
|
// Test Case #0
|
||||||
{"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "0D29F74CCD8640F44B0DD9638111C1B5 766EFED752AF358109E2E7C9CD4A28EF 2F90B2AD461FBA0744D4", 42},
|
{"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "0D29F74CCD8640F44B0DD9638111C1B5 766EFED752AF358109E2E7C9CD4A28EF 2F90B2AD461FBA0744D4", 42},
|
||||||
|
|
@ -779,6 +780,75 @@ bool ValidateHKDF()
|
||||||
return pass;
|
return pass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Scrypt_TestTuple
|
||||||
|
{
|
||||||
|
const char * passwd;
|
||||||
|
const char * salt;
|
||||||
|
uint64_t n;
|
||||||
|
uint32_t r;
|
||||||
|
uint32_t p;
|
||||||
|
const char * expect;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool TestScrypt(KeyDerivationFunction &pbkdf, const Scrypt_TestTuple *testSet, unsigned int testSetSize)
|
||||||
|
{
|
||||||
|
bool pass = true;
|
||||||
|
|
||||||
|
for (unsigned int i=0; i<testSetSize; i++)
|
||||||
|
{
|
||||||
|
const Scrypt_TestTuple &tuple = testSet[i];
|
||||||
|
|
||||||
|
std::string password(tuple.passwd), salt(tuple.salt), expect;
|
||||||
|
StringSource(tuple.expect, true, new HexDecoder(new StringSink(expect)));
|
||||||
|
|
||||||
|
AlgorithmParameters params = MakeParameters("Cost", (word64)tuple.n)
|
||||||
|
("BlockSize", (word64)tuple.r)("Parallelization", (word64)tuple.p)
|
||||||
|
(Name::Salt(), ConstByteArrayParameter((const byte*)&salt[0], salt.size()));
|
||||||
|
|
||||||
|
SecByteBlock derived(expect.size());
|
||||||
|
pbkdf.DeriveKey(derived, derived.size(), (const byte *)password.data(), password.size(), params);
|
||||||
|
bool fail = !!memcmp(derived, expect.data(), expect.size()) != 0;
|
||||||
|
pass = pass && !fail;
|
||||||
|
|
||||||
|
if (password.empty()) {password="\"\"";}
|
||||||
|
if (salt.empty()) {salt="\"\"";}
|
||||||
|
|
||||||
|
HexEncoder enc(new FileSink(std::cout));
|
||||||
|
std::cout << (fail ? "FAILED " : "passed ");
|
||||||
|
std::cout << " " << password << " " << salt << " ";
|
||||||
|
std::cout << " " << tuple.n << " " << tuple.r;
|
||||||
|
std::cout << " " << tuple.p << " ";
|
||||||
|
enc.Put(derived, derived.size());
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ValidateScrypt()
|
||||||
|
{
|
||||||
|
bool pass = true;
|
||||||
|
|
||||||
|
// https://tools.ietf.org/html/rfc7914
|
||||||
|
const Scrypt_TestTuple testSet[] =
|
||||||
|
{
|
||||||
|
{ "", "", 16, 1, 1, "77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906"},
|
||||||
|
{ "password", "NaCl", 1024, 8, 16, "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640"},
|
||||||
|
{ "pleaseletmein", "SodiumChloride", 16384, 8, 1, "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887"},
|
||||||
|
#ifndef CRYPTOPP_DEBUG
|
||||||
|
// This one takes too long in debug builds
|
||||||
|
{ "pleaseletmein", "SodiumChloride", 1048576, 8, 1, "2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049e8a952fbcbf45c6fa77a41a4"}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
Scrypt pbkdf;
|
||||||
|
|
||||||
|
std::cout << "\nRFC 7914 Scrypt validation suite running...\n\n";
|
||||||
|
pass = TestScrypt(pbkdf, testSet, COUNTOF(testSet)) && pass;
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
struct Poly1305_TestTuples
|
struct Poly1305_TestTuples
|
||||||
{
|
{
|
||||||
const char *key, *message, *nonce, *digest;
|
const char *key, *message, *nonce, *digest;
|
||||||
|
|
@ -797,7 +867,7 @@ bool ValidatePoly1305()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test data from http://cr.yp.to/mac/poly1305-20050329.pdf
|
// Test data from http://cr.yp.to/mac/poly1305-20050329.pdf
|
||||||
static const Poly1305_TestTuples tests[] =
|
const Poly1305_TestTuples tests[] =
|
||||||
{
|
{
|
||||||
// Appendix B, Test 1
|
// Appendix B, Test 1
|
||||||
{
|
{
|
||||||
|
|
@ -1094,7 +1164,7 @@ bool ValidateBLAKE2s()
|
||||||
pass = pass && !fail;
|
pass = pass && !fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const BLAKE2_TestTuples tests[] = {
|
const BLAKE2_TestTuples tests[] = {
|
||||||
{
|
{
|
||||||
NULLPTR,
|
NULLPTR,
|
||||||
NULLPTR,
|
NULLPTR,
|
||||||
|
|
@ -1525,7 +1595,7 @@ bool ValidateBLAKE2b()
|
||||||
pass = pass && !fail;
|
pass = pass && !fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const BLAKE2_TestTuples tests[] = {
|
const BLAKE2_TestTuples tests[] = {
|
||||||
{
|
{
|
||||||
NULLPTR,
|
NULLPTR,
|
||||||
NULLPTR,
|
NULLPTR,
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ bool ValidateTTMAC();
|
||||||
bool ValidateCipherModes();
|
bool ValidateCipherModes();
|
||||||
bool ValidatePBKDF();
|
bool ValidatePBKDF();
|
||||||
bool ValidateHKDF();
|
bool ValidateHKDF();
|
||||||
|
bool ValidateScrypt();
|
||||||
|
|
||||||
bool ValidateDES();
|
bool ValidateDES();
|
||||||
bool ValidateIDEA();
|
bool ValidateIDEA();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue