diff --git a/Foundation/Foundation_CE_vs90.vcproj b/Foundation/Foundation_CE_vs90.vcproj index af3ea3de6..a412bccf0 100644 --- a/Foundation/Foundation_CE_vs90.vcproj +++ b/Foundation/Foundation_CE_vs90.vcproj @@ -1885,6 +1885,10 @@ RelativePath=".\include\Poco\MD5Engine.h" > + + diff --git a/Foundation/Foundation_vs71.vcproj b/Foundation/Foundation_vs71.vcproj index 910ee8ce3..9ef2e8327 100644 --- a/Foundation/Foundation_vs71.vcproj +++ b/Foundation/Foundation_vs71.vcproj @@ -1922,6 +1922,9 @@ + + diff --git a/Foundation/Foundation_vs80.vcproj b/Foundation/Foundation_vs80.vcproj index a7ddc0186..de1b2c4fe 100644 --- a/Foundation/Foundation_vs80.vcproj +++ b/Foundation/Foundation_vs80.vcproj @@ -2463,6 +2463,10 @@ RelativePath=".\include\Poco\MD5Engine.h" > + + diff --git a/Foundation/Foundation_vs90.vcproj b/Foundation/Foundation_vs90.vcproj index f549151e8..24c2b6280 100644 --- a/Foundation/Foundation_vs90.vcproj +++ b/Foundation/Foundation_vs90.vcproj @@ -2456,6 +2456,10 @@ RelativePath=".\include\Poco\MD5Engine.h" > + + diff --git a/Foundation/Foundation_x64_vs90.vcproj b/Foundation/Foundation_x64_vs90.vcproj index f7b853c32..4fab86836 100644 --- a/Foundation/Foundation_x64_vs90.vcproj +++ b/Foundation/Foundation_x64_vs90.vcproj @@ -2458,6 +2458,10 @@ RelativePath=".\include\Poco\MD5Engine.h" > + + diff --git a/Foundation/include/Poco/PBKDF2Engine.h b/Foundation/include/Poco/PBKDF2Engine.h new file mode 100644 index 000000000..2a665fd4b --- /dev/null +++ b/Foundation/include/Poco/PBKDF2Engine.h @@ -0,0 +1,171 @@ +// +// PBKDF2Engine.h +// +// $Id: //poco/1.4/Foundation/include/Poco/PBKDF2Engine.h#1 $ +// +// Library: Foundation +// Package: Crypt +// Module: PBKDF2Engine +// +// Definition of the PBKDF2Engine class. +// +// Copyright (c) 2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Foundation_PBKDF2Engine_INCLUDED +#define Foundation_PBKDF2Engine_INCLUDED + + +#include "Poco/Foundation.h" +#include "Poco/DigestEngine.h" +#include "Poco/ByteOrder.h" +#include + + +namespace Poco { + + +template +class PBKDF2Engine: public DigestEngine + /// This class implementes the Password-Based Key Derivation Function 2, + /// as specified in RFC 2898. The underlying DigestEngine (HMACEngine, etc.), + /// which must accept the passphrase as constructor argument (std::string), + /// must be given as template argument. + /// + /// PBKDF2 (Password-Based Key Derivation Function 2) is a key derivation function + /// that is part of RSA Laboratories' Public-Key Cryptography Standards (PKCS) series, + /// specifically PKCS #5 v2.0, also published as Internet Engineering Task Force's + /// RFC 2898. It replaces an earlier standard, PBKDF1, which could only produce + /// derived keys up to 160 bits long. + /// + /// PBKDF2 applies a pseudorandom function, such as a cryptographic hash, cipher, or + /// HMAC to the input password or passphrase along with a salt value and repeats the + /// process many times to produce a derived key, which can then be used as a + /// cryptographic key in subsequent operations. The added computational work makes + /// password cracking much more difficult, and is known as key stretching. + /// When the standard was written in 2000, the recommended minimum number of + /// iterations was 1000, but the parameter is intended to be increased over time as + /// CPU speeds increase. Having a salt added to the password reduces the ability to + /// use precomputed hashes (rainbow tables) for attacks, and means that multiple + /// passwords have to be tested individually, not all at once. The standard + /// recommends a salt length of at least 64 bits. [Wikipedia] + /// + /// The PBKDF2 algorithm is implemented as a DigestEngine. The passphrase is specified + /// by calling update(). + /// + /// Example (WPA2): + /// PBKDF2Engine > pbkdf2(ssid, 4096, 256); + /// pbkdf2.update(passphrase); + /// DigestEngine::Digest d = pbkdf2.digest(); +{ +public: + enum + { + PRF_DIGEST_SIZE = PRF::DIGEST_SIZE + }; + + PBKDF2Engine(const std::string& salt, unsigned c = 4096, Poco::UInt32 dkLen = PRF_DIGEST_SIZE): + _s(salt), + _c(c), + _dkLen(dkLen) + { + _result.reserve(_dkLen + PRF_DIGEST_SIZE); + } + + ~PBKDF2Engine() + { + } + + std::size_t digestLength() const + { + return _dkLen; + } + + void reset() + { + _p.clear(); + _result.clear(); + } + + const DigestEngine::Digest& digest() + { + Poco::UInt32 i = 1; + while (_result.size() < _dkLen) + { + f(i++); + } + _result.resize(_dkLen); + return _result; + } + +protected: + void updateImpl(const void* data, std::size_t length) + { + _p.append(reinterpret_cast(data), length); + } + + void f(Poco::UInt32 i) + { + PRF prf(_p); + prf.update(_s); + Poco::UInt32 iBE = Poco::ByteOrder::toBigEndian(i); + prf.update(&iBE, sizeof(iBE)); + Poco::DigestEngine::Digest up = prf.digest(); + Poco::DigestEngine::Digest ux = up; + poco_assert_dbg(ux.size() == PRF_DIGEST_SIZE); + for (unsigned k = 1; k < _c; k++) + { + prf.reset(); + prf.update(&up[0], up.size()); + Poco::DigestEngine::Digest u = prf.digest(); + poco_assert_dbg(u.size() == PRF_DIGEST_SIZE); + for (int ui = 0; ui < PRF_DIGEST_SIZE; ui++) + { + ux[ui] ^= u[ui]; + } + std::swap(up, u); + } + _result.insert(_result.end(), ux.begin(), ux.end()); + } + +private: + PBKDF2Engine(); + PBKDF2Engine(const PBKDF2Engine&); + PBKDF2Engine& operator = (const PBKDF2Engine&); + + std::string _p; + std::string _s; + unsigned _c; + Poco::UInt32 _dkLen; + DigestEngine::Digest _result; +}; + + +} // namespace Poco + + +#endif // Foundation_PBKDF2Engine_INCLUDED diff --git a/Foundation/testsuite/Makefile-Driver b/Foundation/testsuite/Makefile-Driver index 8e20d10b8..f6e6ed18b 100644 --- a/Foundation/testsuite/Makefile-Driver +++ b/Foundation/testsuite/Makefile-Driver @@ -22,7 +22,7 @@ objects = ActiveMethodTest ActivityTest ActiveDispatcherTest \ NDCTest NotificationCenterTest NotificationQueueTest \ PriorityNotificationQueueTest TimedNotificationQueueTest \ NotificationsTestSuite NullStreamTest NumberFormatterTest \ - NumberParserTest PathTest PatternFormatterTest RWLockTest \ + NumberParserTest PathTest PatternFormatterTest PBKDF2EngineTest RWLockTest \ RandomStreamTest RandomTest RegularExpressionTest SHA1EngineTest \ SemaphoreTest ConditionTest SharedLibraryTest SharedLibraryTestSuite \ SimpleFileChannelTest StopwatchTest \ diff --git a/Foundation/testsuite/TestSuite_CE_vs90.vcproj b/Foundation/testsuite/TestSuite_CE_vs90.vcproj index 4d73e19c6..9574a7552 100644 --- a/Foundation/testsuite/TestSuite_CE_vs90.vcproj +++ b/Foundation/testsuite/TestSuite_CE_vs90.vcproj @@ -942,6 +942,10 @@ RelativePath=".\src\MD5EngineTest.cpp" > + + @@ -978,6 +982,10 @@ RelativePath=".\src\MD5EngineTest.h" > + + diff --git a/Foundation/testsuite/TestSuite_vs71.vcproj b/Foundation/testsuite/TestSuite_vs71.vcproj index 75f3d325b..dddcc36db 100644 --- a/Foundation/testsuite/TestSuite_vs71.vcproj +++ b/Foundation/testsuite/TestSuite_vs71.vcproj @@ -670,6 +670,9 @@ + + @@ -698,6 +701,9 @@ + + diff --git a/Foundation/testsuite/TestSuite_vs80.vcproj b/Foundation/testsuite/TestSuite_vs80.vcproj index 636184cae..f530a6376 100644 --- a/Foundation/testsuite/TestSuite_vs80.vcproj +++ b/Foundation/testsuite/TestSuite_vs80.vcproj @@ -911,6 +911,10 @@ RelativePath=".\src\MD5EngineTest.cpp" > + + @@ -947,6 +951,10 @@ RelativePath=".\src\MD5EngineTest.h" > + + diff --git a/Foundation/testsuite/TestSuite_vs90.vcproj b/Foundation/testsuite/TestSuite_vs90.vcproj index 141c45e6b..5af19b129 100644 --- a/Foundation/testsuite/TestSuite_vs90.vcproj +++ b/Foundation/testsuite/TestSuite_vs90.vcproj @@ -897,6 +897,10 @@ RelativePath=".\src\MD5EngineTest.cpp" > + + @@ -933,6 +937,10 @@ RelativePath=".\src\MD5EngineTest.h" > + + diff --git a/Foundation/testsuite/TestSuite_x64_vs90.vcproj b/Foundation/testsuite/TestSuite_x64_vs90.vcproj index 95aede499..b3732cbba 100644 --- a/Foundation/testsuite/TestSuite_x64_vs90.vcproj +++ b/Foundation/testsuite/TestSuite_x64_vs90.vcproj @@ -891,6 +891,10 @@ RelativePath=".\src\MD5EngineTest.cpp" > + + @@ -927,6 +931,10 @@ RelativePath=".\src\MD5EngineTest.h" > + + diff --git a/Foundation/testsuite/src/CryptTestSuite.cpp b/Foundation/testsuite/src/CryptTestSuite.cpp index ec602e9ea..2ac79bb46 100644 --- a/Foundation/testsuite/src/CryptTestSuite.cpp +++ b/Foundation/testsuite/src/CryptTestSuite.cpp @@ -35,6 +35,7 @@ #include "MD5EngineTest.h" #include "SHA1EngineTest.h" #include "HMACEngineTest.h" +#include "PBKDF2EngineTest.h" #include "DigestStreamTest.h" #include "RandomTest.h" #include "RandomStreamTest.h" @@ -48,6 +49,7 @@ CppUnit::Test* CryptTestSuite::suite() pSuite->addTest(MD5EngineTest::suite()); pSuite->addTest(SHA1EngineTest::suite()); pSuite->addTest(HMACEngineTest::suite()); + pSuite->addTest(PBKDF2EngineTest::suite()); pSuite->addTest(DigestStreamTest::suite()); pSuite->addTest(RandomTest::suite()); pSuite->addTest(RandomStreamTest::suite()); diff --git a/Foundation/testsuite/src/PBKDF2EngineTest.cpp b/Foundation/testsuite/src/PBKDF2EngineTest.cpp new file mode 100644 index 000000000..0a225c32c --- /dev/null +++ b/Foundation/testsuite/src/PBKDF2EngineTest.cpp @@ -0,0 +1,157 @@ +// +// PBKDF2EngineTest.cpp +// +// $Id: //poco/1.4/Foundation/testsuite/src/PBKDF2EngineTest.cpp#1 $ +// +// Copyright (c) 2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "PBKDF2EngineTest.h" +#include "CppUnit/TestCaller.h" +#include "CppUnit/TestSuite.h" +#include "Poco/PBKDF2Engine.h" +#include "Poco/HMACEngine.h" +#include "Poco/SHA1Engine.h" + + +using Poco::PBKDF2Engine; +using Poco::HMACEngine; +using Poco::SHA1Engine; +using Poco::DigestEngine; + + +PBKDF2EngineTest::PBKDF2EngineTest(const std::string& name): CppUnit::TestCase(name) +{ +} + + +PBKDF2EngineTest::~PBKDF2EngineTest() +{ +} + + +void PBKDF2EngineTest::testPBKDF2a() +{ + // test vector 1 from RFC 6070 + + std::string p("password"); + std::string s("salt"); + PBKDF2Engine > pbkdf2(s, 1, 20); + pbkdf2.update(p); + std::string dk = DigestEngine::digestToHex(pbkdf2.digest()); + assert (dk == "0c60c80f961f0e71f3a9b524af6012062fe037a6"); +} + + +void PBKDF2EngineTest::testPBKDF2b() +{ + // test vector 2 from RFC 6070 + + std::string p("password"); + std::string s("salt"); + PBKDF2Engine > pbkdf2(s, 2, 20); + pbkdf2.update(p); + std::string dk = DigestEngine::digestToHex(pbkdf2.digest()); + assert (dk == "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"); +} + + +void PBKDF2EngineTest::testPBKDF2c() +{ + // test vector 3 from RFC 6070 + + std::string p("password"); + std::string s("salt"); + PBKDF2Engine > pbkdf2(s, 4096, 20); + pbkdf2.update(p); + std::string dk = DigestEngine::digestToHex(pbkdf2.digest()); + assert (dk == "4b007901b765489abead49d926f721d065a429c1"); +} + + +void PBKDF2EngineTest::testPBKDF2d() +{ + // test vector 4 from RFC 6070 + + std::string p("password"); + std::string s("salt"); + PBKDF2Engine > pbkdf2(s, 16777216, 20); + pbkdf2.update(p); + std::string dk = DigestEngine::digestToHex(pbkdf2.digest()); + assert (dk == "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984"); +} + + +void PBKDF2EngineTest::testPBKDF2e() +{ + // test vector 5 from RFC 6070 + + std::string p("passwordPASSWORDpassword"); + std::string s("saltSALTsaltSALTsaltSALTsaltSALTsalt"); + PBKDF2Engine > pbkdf2(s, 4096, 25); + pbkdf2.update(p); + std::string dk = DigestEngine::digestToHex(pbkdf2.digest()); + assert (dk == "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"); +} + + +void PBKDF2EngineTest::testPBKDF2f() +{ + // test vector 6 from RFC 6070 + + std::string p("pass\0word", 9); + std::string s("sa\0lt", 5); + PBKDF2Engine > pbkdf2(s, 4096, 16); + pbkdf2.update(p); + std::string dk = DigestEngine::digestToHex(pbkdf2.digest()); + assert (dk == "56fa6aa75548099dcc37d7f03425e0c3"); +} + + +void PBKDF2EngineTest::setUp() +{ +} + + +void PBKDF2EngineTest::tearDown() +{ +} + + +CppUnit::Test* PBKDF2EngineTest::suite() +{ + CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("PBKDF2EngineTest"); + + CppUnit_addTest(pSuite, PBKDF2EngineTest, testPBKDF2a); + CppUnit_addTest(pSuite, PBKDF2EngineTest, testPBKDF2b); + CppUnit_addTest(pSuite, PBKDF2EngineTest, testPBKDF2c); + CppUnit_addTest(pSuite, PBKDF2EngineTest, testPBKDF2d); + CppUnit_addTest(pSuite, PBKDF2EngineTest, testPBKDF2e); + CppUnit_addTest(pSuite, PBKDF2EngineTest, testPBKDF2f); + + return pSuite; +} diff --git a/Foundation/testsuite/src/PBKDF2EngineTest.h b/Foundation/testsuite/src/PBKDF2EngineTest.h new file mode 100644 index 000000000..13be75182 --- /dev/null +++ b/Foundation/testsuite/src/PBKDF2EngineTest.h @@ -0,0 +1,65 @@ +// +// PBKDF2EngineTest.h +// +// $Id: //poco/1.4/Foundation/testsuite/src/PBKDF2EngineTest.h#1 $ +// +// Definition of the PBKDF2EngineTest class. +// +// Copyright (c) 2014, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef PBKDF2EngineTest_INCLUDED +#define PBKDF2EngineTest_INCLUDED + + +#include "Poco/Foundation.h" +#include "CppUnit/TestCase.h" + + +class PBKDF2EngineTest: public CppUnit::TestCase +{ +public: + PBKDF2EngineTest(const std::string& name); + ~PBKDF2EngineTest(); + + void testPBKDF2a(); + void testPBKDF2b(); + void testPBKDF2c(); + void testPBKDF2d(); + void testPBKDF2e(); + void testPBKDF2f(); + + void setUp(); + void tearDown(); + + static CppUnit::Test* suite(); + +private: +}; + + +#endif // PBKDF2EngineTest_INCLUDED