8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 20:43:02 +01:00

Applied CORE-5788: Security Patch: Replacement of use of SHA-1 in the SRP Client Proof with SHA-256

This commit is contained in:
Alex Peshkoff 2018-06-21 14:49:16 +03:00
parent 76a55ab9b6
commit b9a93f5312
15 changed files with 1592 additions and 51 deletions

View File

@ -422,13 +422,19 @@
#
# Type: string
# AuthServer and AuthClient determine what authentication methods will be used
# by network server and client redirector. Secure remote passwords plugin
# is default one. Except configured by default SRP plugin firebird also has
# Legacy_Auth plugin which is used to emulate pre-FB3 login protocol making it
# possible for client to talk to old servers and for server to listen to requests
# from old clients. Legacy_Auth is VERY unsecure. On windows Win_Sspi plugin may
# be also used - it implements windows trusted authentication and backward
# AuthServer and AuthClient determine which authentication methods will be used
# by network server and client redirector. The Secure remote password plugin
# using SHA-256 for the client proof is the default for both client and Server.
# Additionally, the default client configuration (AuthClient) also supports old Srp
# plugin using SHA-1 for the client proof. This enables backwards compatibility
# with old Firebird 3 servers but does not comply with NIST security requirements.
#
# The default client configuration (AuthClient) also supports the pre-Firebird 3 legacy
# authentication protocol (Legacy_Auth). This is again for backwards
# compatibility but has many known weaknesses and is deprecated for current use.
#
# The default Windows client configuration (AuthClient) also includes support for
# the Win_Sspi plugin. This implements windows trusted authentication and is backward
# compatible with 2.1 and 2.5 clients and servers running on windows.
#
# Per-database configurable.
@ -437,7 +443,8 @@
#
# Per-connection and per-database configurable.
#
#AuthClient = Srp, Win_Sspi, Legacy_Auth
#AuthClient = Srp, Srp256, Legacy_Auth #Non Windows clients
#AuthClient = Srp, Srp256, Win_Sspi, Legacy_Auth #Windows clients
#
# If you need to use server plugins that do not provide encryption key (both Legacy_Auth
# & Win_Sspi) you should also turn off required encryption on the wire with WireCrypt

View File

@ -27,7 +27,7 @@ AllObjects=
CO1:= $(call dirObjects,common)
CO2:= $(call dirObjects,common/classes)
CO3:= $(call dirObjects,common/config)
CO4:= $(call dirObjects,common/tomcrypt)
CO4:= $(call dirObjects,common/sha2)
#CO5:= $(call dirObjects,common/exceptions)
#CO6:= $(call dirObjects,common/sync)
Common_Objects:= $(CO1) $(CO2) $(CO3) $(CO4)

View File

@ -0,0 +1,204 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>- no title specified</title>
<meta name="generator" content="LibreOffice 5.1.6.2 (Linux)"/>
<meta name="created" content="00:00:00"/>
<meta name="changed" content="2018-06-21T14:25:04.182337599"/>
<meta name="DCTERMS.issued" content="2018-04-09T10:14:20.507318741"/>
<meta name="DCTERMS.language" content="en-US"/>
<meta name="DCTERMS.modified" content="2018-04-09T10:14:29.569131327"/>
<meta name="DCTERMS.provenance" content=""/>
<meta name="DCTERMS.source" content="http://xml.openoffice.org/odf2xhtml"/>
<meta name="DCTERMS.subject" content=","/>
<meta name="DCTERMS.title" content=""/>
<style type="text/css">
p { margin-left: 0.79in; margin-right: 0.79in; color: #000000 }
td p { margin-left: 0.79in; margin-right: 0.79in; color: #000000; font-size: 12pt }
h1 { margin-left: 0.79in; margin-right: 0.79in; color: #000000 }
h2 { margin-left: 0.79in; margin-right: 0.79in; color: #000000 }
h2.cjk { font-family: "Noto Sans CJK SC Regular" }
h2.ctl { font-family: "FreeSans" }
p.p1 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
p.p4 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
td p.p6 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
p.p5 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
p.p7 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
p.p2 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
p.p9 { margin-bottom: 0.1in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
p.p10 { margin-bottom: 0in; font-family: "Liberation Serif"; font-size: 12pt; line-height: 120% }
</style>
</head>
<body lang="en-US" text="#000000" dir="ltr">
<p>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<!--This file was converted to xhtml by LibreOffice - see http://cgit.freedesktop.org/libreoffice/core/tree/filter/source/xslt for the code.-->
</p>
<h1><a name="a__Replacement_of_use_of_SHA-1_in_the_SRP_Client_Proof_with_a_SHA-2_Message_Digest"></a>
Replacement of use of SHA-1 in the SRP Client Proof with a SHA-2
Message Digest</h1>
<p class="p1">The Firebird implementation of the Secure Remote
Protocol (SRP) for password based user authentication has been
updated following a security review of the original Firebird SRP-6a
implementation taking into account current NIST guidance on the use
of SHA-1 see NIST Special Publication 800-131A, Revision 1,
Transitions: Recommendation for Transitioning the Use of
Cryptographic Algorithms and Key Lengths
(<a href="http://dx.doi.org/10.6028/NIST.SP.800-131Ar1">http://dx.doi.org/10.6028/NIST.SP.800-131Ar1</a>)
chapter 9. This guidance disallows the general use of SHA-1 for
“Digital Signature Generation” whilst permitting continued use
for “Digital Signature Verification”. The background to making
this change is given below.</p>
<p class="p4">By default, the SHA-256 message digest is now used
instead of SHA-1 for generating the Client Proof. Alternatively,
SHA-1 (deprecated and for legacy use only) may be used for the Client
Proof. Separate AuthServer and AuthClient plugins are available for
each supported message digest, with the following names:</p>
<table width="703" cellpadding="0" cellspacing="0">
<col width="174">
<col width="528">
<tr>
<td width="174" style="border: none; padding: 0in">
<ul>
<li/>
<p class="p6" align="left" style="margin-right: 0in">•Srp&nbsp;</p>
</ul>
</td>
<td width="528" style="border: none; padding: 0in">
<p class="p4" align="left">SHA-1 Client Proof</p>
</td>
</tr>
<tr>
<td width="174" style="border: none; padding: 0in">
<ul>
<li/>
<p class="p6" align="left" style="margin-right: 0in">•Srp256&nbsp;</p>
</ul>
</td>
<td width="528" style="border: none; padding: 0in">
<p class="p4" align="left">SHA-256 Client Proof</p>
</td>
</tr>
</table>
<p class="p5">Both client and server must have an SRP authentication
plugin in common in order to enable successfully authentication of a
user's password.
</p>
<p class="p5">There is no change to the SRP User Manager. This is
still called (“Srp”) and the User Manager and the security
database are not affected by the choice of message digest used to
compute the client proof.</p>
<p class="p4">The “firebird.conf” default configuration file
entries for AuthServer and AuthClient are now:</p>
<p class="p4">AuthServer = Srp256<br/>
AuthClient = Srp256, Srp,
Legacy_Auth (Non -windows clients)<br/>
AuthClient = Srp256, Srp,
Win_Sspi, Legacy_Auth (windows clients)</p>
<p class="p4">With these settings, a Firebird Server is using Srp256
to authenticate a client using SHA-256 to compute the client proof
and is thus compatible with Firebird 3.0.4 or newer clients. On the
other hand, a Firebird client will authenticate the user with any
server version down to at least 2.5.</p>
<p class="p7">A deployment where both client and servers support the
legacy Srp (using SHA-1) and one or more of the SHA-2 authentication
plugins (e.g. Srp256) should be avoided. This is because an attacker
might be able to disrupt the Srp256 authentication thereby forcing
Firebird to use the weaker Srp SHA-1 client proof without the user
being aware.</p>
<h2 class="western"><a name="a__REASON_FOR_CHANGE"></a>REASON FOR
CHANGE</h2>
<p class="p1">Review of the Firebird SRP implementation appears to
indicate that most uses of SHA-1 continue to be permitted under NIST
guidance except for its use in generating the client proof. The SRP
client proof may be characterised as a “Poor Man's Digital
Signature” in that it provides a two party proof of identity rather
than the third party proof normally expected from a Digital Signature
i.e. it is not a non-repudiable proof. Nevertheless, it is believed
that generation of the client proof falls under the heading of
“Digital Signature Generation” when considering the NIST
Guidance.</p>
<p class="p2">Continued use of SHA-1 in order to generate the client
proof appears to risk leakage of the encryption key used to encrypt
“over-the-wire” encryption and which hence also provides peer
entity authentication during the lifetime of the connection. This may
result in an attacker being able to monitor confidential
communication either during the connection or at some later date and
this could include leakage of an encryption key used to encrypt the
user database, if this is passed from client to server during the
connection.</p>
<p class="p2">Such an attack is viable if weaknesses in SHA-1 can be
exploited to allow a brute force attack on the client proof to be
computationally feasible. All parts of the message on which the
client proof is based may be known to an attacker with the exception
of the shared session key and such an attack would concentrate on
revealing this key. If it were possible to reveal the shared session
key in real time then additionally a man-in-the-middle attack would
be feasible.</p>
<p class="p2">The severity of this issue is viewed as Important but
not Critical. Users that rely on SRP (using SHA-1)/over the wire
encryption to protect confidential communication have a long term
risk that the confidentiality of &nbsp;their data may be compromised.
The attack may also be mitigated through the use of other procedures
to protect communications (e.g. a secure VPN).</p>
<p class="p9">The update adds a new directory to the source code tree
(src/common/sha2) containing an implementation of the SHA-2 family of
message digests derived from the implementation published by Olivier
Gay &lt;<a href="mailto:olivier.gay@a3.epfl.ch">olivier.gay@a3.epfl.ch</a>&gt;
(see https://github.com/ouah/sha2). The following copyright notice is
included at the request of the original author and applies to the
files in src/common/sha2:</p>
<p class="p10" style="margin-bottom: 0.2in">FIPS 180-2
SHA-224/256/384/512 implementation</p>
<p class="p10" style="margin-bottom: 0.2in">Last update: 02/02/2007</p>
<p class="p10" style="margin-bottom: 0.2in">Issue date: &nbsp;04/30/2005</p>
<p class="p10" style="margin-bottom: 0.2in">https://github.com/ouah/sha2</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp;</p>
<p class="p10" style="margin-bottom: 0.2in">Copyright (C) 2005, 2007
Olivier Gay &lt;olivier.gay@a3.epfl.ch&gt;</p>
<p class="p10" style="margin-bottom: 0.2in">All rights reserved.</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp;</p>
<p class="p10" style="margin-bottom: 0.2in">Redistribution and use in
source and binary forms, with or without</p>
<p class="p10" style="margin-bottom: 0.2in">modification, are
permitted provided that the following conditions</p>
<p class="p10" style="margin-bottom: 0.2in">are met:</p>
<p class="p10" style="margin-bottom: 0.2in">1. Redistributions of
source code must retain the above copyright</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp; &nbsp;notice, this
list of conditions and the following disclaimer.</p>
<p class="p10" style="margin-bottom: 0.2in">2. Redistributions in
binary form must reproduce the above copyright</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp; &nbsp;notice, this
list of conditions and the following disclaimer in the</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp; &nbsp;documentation
and/or other materials provided with the distribution.</p>
<p class="p10" style="margin-bottom: 0.2in">3. Neither the name of
the project nor the names of its contributors</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp; &nbsp;may be used
to endorse or promote products derived from this software</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp; &nbsp;without
specific prior written permission.</p>
<p class="p10" style="margin-bottom: 0.2in">&nbsp;</p>
<p class="p10" style="margin-bottom: 0.2in">THIS SOFTWARE IS PROVIDED
BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND</p>
<p class="p10" style="margin-bottom: 0.2in">ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE</p>
<p class="p10" style="margin-bottom: 0.2in">IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE</p>
<p class="p10" style="margin-bottom: 0.2in">ARE DISCLAIMED. &nbsp;IN
NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE</p>
<p class="p10" style="margin-bottom: 0.2in">FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL</p>
<p class="p10" style="margin-bottom: 0.2in">DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS</p>
<p class="p10" style="margin-bottom: 0.2in">OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION)</p>
<p class="p10" style="margin-bottom: 0.2in">HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT</p>
<p class="p10" style="margin-bottom: 0.2in">LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY</p>
<p class="p10" style="margin-bottom: 0.2in">OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF</p>
<p class="p10" style="margin-bottom: 0.2in">SUCH DAMAGE.</p>
</body>
</html>

View File

@ -364,7 +364,7 @@ add_library (burp ${burp_src} ${burp_generated_src_master})
# LIBRARY common
########################################
file(GLOB common_src "common/*.cpp" "common/classes/*.cpp" "common/config/*.cpp" "common/os/${OS_DIR}/*.cpp")
file(GLOB common_src "common/*.cpp" "common/classes/*.cpp" "common/config/*.cpp" "common/os/${OS_DIR}/*.cpp" "common/sha2/*.cpp")
file(GLOB_RECURSE common_include "common/*.h")
if (APPLE)

View File

@ -34,7 +34,7 @@ using namespace Firebird;
namespace Auth {
class SrpClient FB_FINAL : public StdPlugin<IClientImpl<SrpClient, CheckStatusWrapper> >
class SrpClient : public StdPlugin<IClientImpl<SrpClient, CheckStatusWrapper> >
{
public:
explicit SrpClient(IPluginConfig*)
@ -55,6 +55,20 @@ private:
RemotePassword* client;
string data;
UCharBuffer sessionKey;
protected:
virtual RemotePassword* RemotePasswordFactory()=0;
};
template <class SHA> class SrpClientImpl FB_FINAL : public SrpClient
{
public:
explicit SrpClientImpl<SHA>(IPluginConfig* ipc)
: SrpClient(ipc) {}
protected:
RemotePassword* RemotePasswordFactory()
{
return FB_NEW RemotePasswordImpl<SHA>;
}
};
int SrpClient::authenticate(CheckStatusWrapper* status, IClientBlock* cb)
@ -76,7 +90,7 @@ int SrpClient::authenticate(CheckStatusWrapper* status, IClientBlock* cb)
return AUTH_CONTINUE;
}
client = FB_NEW RemotePassword;
client = RemotePasswordFactory();
client->genClientKey(data);
dumpIt("Clnt: clientPubKey", data);
cb->putData(status, data.length(), data.begin());
@ -130,7 +144,7 @@ int SrpClient::authenticate(CheckStatusWrapper* status, IClientBlock* cb)
BigInteger cProof = client->clientProof(cb->getLogin(), salt.c_str(), sessionKey);
cProof.getText(data);
dumpIt("Clnt: Client Proof",cProof);
cb->putData(status, data.length(), data.c_str());
if (status->getState() & IStatus::STATE_ERRORS)
{
@ -170,12 +184,20 @@ int SrpClient::release()
namespace
{
SimpleFactory<SrpClient> factory;
SimpleFactory<SrpClientImpl<Sha1> > factory_sha1;
SimpleFactory<SrpClientImpl<sha224> > factory_sha224;
SimpleFactory<SrpClientImpl<sha256> > factory_sha256;
SimpleFactory<SrpClientImpl<sha384> > factory_sha384;
SimpleFactory<SrpClientImpl<sha512> > factory_sha512;
}
void registerSrpClient(IPluginManager* iPlugin)
{
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, RemotePassword::plugName, &factory);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, RemotePassword::plugName, &factory_sha1);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, RemotePassword::pluginName(224).c_str(), &factory_sha224);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, RemotePassword::pluginName(256).c_str(), &factory_sha256);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, RemotePassword::pluginName(384).c_str(), &factory_sha384);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, RemotePassword::pluginName(512).c_str(), &factory_sha512);
}
} // namespace Auth

View File

@ -688,7 +688,7 @@ private:
Firebird::RefPtr<Firebird::IFirebirdConf> config;
Firebird::RefPtr<Firebird::IAttachment> att;
Firebird::RefPtr<Firebird::ITransaction> tra;
RemotePassword server;
RemotePasswordImpl<Firebird::Sha1> server;
int upCount, delCount;
bool checkCount(Firebird::CheckStatusWrapper* status, int* count, UCHAR item)

View File

@ -4,9 +4,8 @@ compile()
file=test_${1}
g++ -I../../../include -DLINUX -DAMD64 -DDEV_BUILD ${file}.cpp \
../../../../temp/Debug/auth/SecureRemotePassword/srp.o \
../../../../temp/Debug/auth/SecureRemotePassword/BigInteger.o \
../../../../temp/Debug/common.a -ltommath ../../../../gen/Debug/firebird/lib/libfbclient.so \
-Wl,-rpath,../../../../gen/Debug/firebird/lib -lrt -o ${file} && ./${file}
-lpthread -Wl,-rpath,../../../../gen/Debug/firebird/lib -lrt -o ${file} && ./${file}
}
compile srp

View File

@ -2,19 +2,19 @@
using namespace Auth;
int main(int argc, char** argv)
template<class SHA>void runTest(int argc, char** argv)
{
Firebird::string salt;
#if SRP_DEBUG > 1
BigInteger s("02E268803000000079A478A700000002D1A6979000000026E1601C000000054F");
Firebird::BigInteger s("02E268803000000079A478A700000002D1A6979000000026E1601C000000054F");
#else
BigInteger s;
Firebird::BigInteger s;
s.random(128);
#endif
s.getText(salt);
RemotePassword* server = FB_NEW RemotePassword();
RemotePassword* client = FB_NEW RemotePassword();
RemotePassword* server = FB_NEW RemotePasswordImpl<SHA>();
RemotePassword* client = FB_NEW RemotePasswordImpl<SHA>();
const char* account = "SYSDBA";
const char* password = "masterkey";
@ -37,8 +37,20 @@ int main(int argc, char** argv)
client->clientSessionKey(key1, account, salt.c_str(), argc > 1 ? argv[1] : password, serverPubKey.c_str());
server->serverSessionKey(key2, clientPubKey.c_str(), verifier);
BigInteger cProof = client->clientProof(account, salt.c_str(), key1);
BigInteger sProof = server->clientProof(account, salt.c_str(), key2);
Firebird::BigInteger cProof = client->clientProof(account, salt.c_str(), key1);
Firebird::BigInteger sProof = server->clientProof(account, salt.c_str(), key2);
printf("Proof length = %d\n",cProof.length());
printf("%s\n", cProof == sProof ? "OK" : "differ");
}
int main(int argc, char** argv)
{
runTest<Firebird::Sha1>(argc,argv);
runTest<Firebird::sha224>(argc,argv);
runTest<Firebird::sha256>(argc,argv);
runTest<Firebird::sha384>(argc,argv);
runTest<Firebird::sha512>(argc,argv);
}

View File

@ -48,7 +48,7 @@ const unsigned int SZ_LOGIN = 31;
namespace Auth {
class SrpServer FB_FINAL : public StdPlugin<IServerImpl<SrpServer, CheckStatusWrapper> >
class SrpServer : public StdPlugin<IServerImpl<SrpServer, CheckStatusWrapper> >
{
public:
explicit SrpServer(IPluginConfig* par)
@ -68,12 +68,12 @@ public:
void setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback);
int release();
private:
~SrpServer()
{
delete server;
}
private:
RemotePassword* server;
string data;
string account;
@ -84,6 +84,20 @@ private:
RefPtr<IFirebirdConf> config;
const char* secDbName;
ICryptKeyCallback* cryptCallback;
protected:
virtual RemotePassword* RemotePasswordFactory()=0;
};
template <class SHA> class SrpServerImpl FB_FINAL : public SrpServer
{
public:
explicit SrpServerImpl<SHA>(IPluginConfig* ipc)
: SrpServer(ipc) {}
protected:
RemotePassword* RemotePasswordFactory()
{
return FB_NEW RemotePasswordImpl<SHA>;
}
};
int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWriter* writerInterface)
@ -215,7 +229,7 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite
throw;
}
server = FB_NEW RemotePassword;
server = RemotePasswordFactory();
server->genServerKey(serverPubKey, verifier);
// Ready to prepare data for client and calculate session key
@ -248,6 +262,9 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite
proof.assign(val, length);
BigInteger clientProof(proof.c_str());
BigInteger serverProof = server->clientProof(account.c_str(), salt.c_str(), sessionKey);
HANDSHAKE_DEBUG(fprintf(stderr, "Client Proof Received, Length = %d\n", clientProof.length()));
dumpIt("Srv: Client Proof",clientProof);
dumpIt("Srv: Server Proof",serverProof);
if (clientProof == serverProof)
{
// put the record into authentication block
@ -311,12 +328,20 @@ int SrpServer::release()
namespace
{
SimpleFactory<SrpServer> factory;
SimpleFactory<SrpServerImpl<Sha1> > factory_sha1;
SimpleFactory<SrpServerImpl<sha224> > factory_sha224;
SimpleFactory<SrpServerImpl<sha256> > factory_sha256;
SimpleFactory<SrpServerImpl<sha384> > factory_sha384;
SimpleFactory<SrpServerImpl<sha512> > factory_sha512;
}
void registerSrpServer(IPluginManager* iPlugin)
{
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, RemotePassword::plugName, &factory);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, RemotePassword::plugName, &factory_sha1);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, RemotePassword::pluginName(224).c_str(), &factory_sha224);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, RemotePassword::pluginName(256).c_str(), &factory_sha256);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, RemotePassword::pluginName(384).c_str(), &factory_sha384);
iPlugin->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, RemotePassword::pluginName(512).c_str(), &factory_sha512);
}
} // namespace Auth

View File

@ -29,7 +29,7 @@ public:
explicit RemoteGroup(Firebird::MemoryPool&)
: prime(primeStr), generator(genStr), k()
{
Auth::Sha1 hash;
Auth::SecureHash<Firebird::Sha1> hash;
hash.processInt(prime);
if (prime.length() > generator.length())
@ -59,6 +59,13 @@ InitInstance<RemoteGroup> RemoteGroup::group;
const char* RemotePassword::plugName = "Srp";
string RemotePassword::pluginName(unsigned bits)
{
string plg;
plg.printf("%s%u", plugName, bits);
return plg;
}
RemotePassword::RemotePassword()
: group(RemoteGroup::getGroup())
{
@ -187,18 +194,7 @@ BigInteger RemotePassword::clientProof(const char* account, const char* salt, co
hash.reset();
hash.process(account);
hash.getInt(n2);
hash.reset();
hash.processInt(n1); // H(prime) ^ H(g)
hash.processInt(n2); // H(I)
hash.process(salt); // s
hash.processInt(clientPublicKey); // A
hash.processInt(serverPublicKey); // B
hash.process(sessionKey); // K
BigInteger rc;
hash.getInt(rc);
return rc;
return MakeProof(n1,n2,salt,sessionKey);
}
#if SRP_DEBUG > 0

View File

@ -2,6 +2,7 @@
#include "../common/classes/alloc.h"
#include "../common/classes/fb_string.h"
#include "../common/sha.h"
#include "../common/sha2/sha2.h"
#define SRP_DEBUG 0 // >0 - prints some debug info
// >1 - uses consts instead randoms, NEVER use in PRODUCTION!
@ -46,13 +47,13 @@ namespace Auth {
class RemoteGroup;
class Sha1 : public Firebird::Sha1
template <class SHA> class SecureHash : public SHA
{
public:
void getInt(Firebird::BigInteger& hash)
{
Firebird::UCharBuffer tmp;
getHash(tmp);
SHA::getHash(tmp);
hash.assign(tmp.getCount(), tmp.begin());
}
@ -60,7 +61,7 @@ public:
{
Firebird::UCharBuffer bytes;
data.getBytes(bytes);
process(bytes);
SHA::process(bytes);
}
void processStrippedInt(const Firebird::BigInteger& data)
@ -70,19 +71,24 @@ public:
if (bytes.getCount())
{
unsigned int n = (bytes[0] == 0) ? 1u : 0;
process(bytes.getCount() - n, bytes.begin() + n);
SHA::process(bytes.getCount() - n, bytes.begin() + n);
}
}
};
class RemotePassword : public Firebird::GlobalStorage
{
private:
const RemoteGroup* group;
Auth::Sha1 hash;
Auth::SecureHash<Firebird::Sha1> hash;
Firebird::BigInteger privateKey;
Firebird::BigInteger scramble;
protected:
virtual Firebird::BigInteger MakeProof(const Firebird::BigInteger n1, const Firebird::BigInteger n2,
const char* salt, const Firebird::UCharBuffer& sessionKey) = 0;
public:
Firebird::BigInteger clientPublicKey;
Firebird::BigInteger serverPublicKey;
@ -95,6 +101,8 @@ public:
static const unsigned SRP_VERIFIER_SIZE = SRP_KEY_SIZE;
static const unsigned SRP_SALT_SIZE = 32;
static Firebird::string pluginName(unsigned bits);
Firebird::BigInteger getUserHash(const char* account,
const char* salt,
const char* password);
@ -115,6 +123,27 @@ public:
const Firebird::UCharBuffer& sessionKey);
};
template <class SHA> class RemotePasswordImpl : public RemotePassword
{
protected:
Firebird::BigInteger MakeProof(const Firebird::BigInteger n1, const Firebird::BigInteger n2,
const char* salt, const Firebird::UCharBuffer& sessionKey)
{
Auth::SecureHash<SHA> digest;
digest.processInt(n1); // H(prime) ^ H(g)
digest.processInt(n2); // H(I)
digest.process(salt); // s
digest.processInt(clientPublicKey); // A
digest.processInt(serverPublicKey); // B
digest.process(sessionKey); // K
Firebird::BigInteger rc;
digest.getInt(rc);
return rc;
}
};
#if SRP_DEBUG > 0
void dumpIt(const char* name, const Firebird::BigInteger& bi);

View File

@ -181,11 +181,11 @@ const Config::ConfigEntry Config::entries[MAX_CONFIG_KEY] =
{TYPE_INTEGER, "MaxUserTraceLogSize", (ConfigValue) 10}, // maximum size of user session trace log
{TYPE_INTEGER, "FileSystemCacheSize", (ConfigValue) 0}, // percent
{TYPE_STRING, "Providers", (ConfigValue) "Remote, " CURRENT_ENGINE ", Loopback"},
{TYPE_STRING, "AuthServer", (ConfigValue) "Srp"},
{TYPE_STRING, "AuthServer", (ConfigValue) "Srp256"},
#ifdef WIN_NT
{TYPE_STRING, "AuthClient", (ConfigValue) "Srp, Win_Sspi, Legacy_Auth"},
{TYPE_STRING, "AuthClient", (ConfigValue) "Srp256, Srp, Win_Sspi, Legacy_Auth"},
#else
{TYPE_STRING, "AuthClient", (ConfigValue) "Srp, Legacy_Auth"},
{TYPE_STRING, "AuthClient", (ConfigValue) "Srp256, Srp, Legacy_Auth"},
#endif
{TYPE_STRING, "UserManager", (ConfigValue) "Srp"},
{TYPE_STRING, "TracePlugin", (ConfigValue) "fbtrace"},

17
src/common/sha2/ChangeLog Normal file
View File

@ -0,0 +1,17 @@
2007-02-02 Olivier Gay <olivier.gay@a3.epfl.ch>
* sha2.c (sha512_transf) [UNROLL_LOOPS]: Group together SHA512_EXP calls
in a loop to optimize speed in SHA-384 and SHA-512.
* sha2.h, sha2.c: Remove HAVE_STDINT and use new typedef for fixed-width
integer types.
2007-02-02 Tad <sha2@ds3switch.com>
* sha2.c (sha224_update, sha256_update, sha384_update, sha512_update): Check
the read size is within the buffer limits when updating small data.
2005-05-23 Olivier Gay <olivier.gay@a3.epfl.ch>
* sha2.h, sha2.c: Support of SHA-224 functions.

954
src/common/sha2/sha2.cpp Normal file
View File

@ -0,0 +1,954 @@
/*
* FIPS 180-2 SHA-224/256/384/512 implementation
* Last update: 02/02/2007
* Issue date: 04/30/2005
* https://github.com/ouah/sha2
*
* Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* Updated for use in Firebird by Tony Whyman <tony@mwasoftware.co.uk>
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if 0
#define UNROLL_LOOPS /* Enable loops unrolling */
#endif
#include "sha2.h"
#define SHFR(x, n) (x >> n)
#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
#define CH(x, y, z) ((x & y) ^ (~x & z))
#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3))
#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
#define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39))
#define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41))
#define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7))
#define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6))
#define UNPACK32(x, str) \
{ \
*((str) + 3) = (uint8) ((x) ); \
*((str) + 2) = (uint8) ((x) >> 8); \
*((str) + 1) = (uint8) ((x) >> 16); \
*((str) + 0) = (uint8) ((x) >> 24); \
}
#define PACK32(str, x) \
{ \
*(x) = ((uint32) *((str) + 3) ) \
| ((uint32) *((str) + 2) << 8) \
| ((uint32) *((str) + 1) << 16) \
| ((uint32) *((str) + 0) << 24); \
}
#define UNPACK64(x, str) \
{ \
*((str) + 7) = (uint8) ((x) ); \
*((str) + 6) = (uint8) ((x) >> 8); \
*((str) + 5) = (uint8) ((x) >> 16); \
*((str) + 4) = (uint8) ((x) >> 24); \
*((str) + 3) = (uint8) ((x) >> 32); \
*((str) + 2) = (uint8) ((x) >> 40); \
*((str) + 1) = (uint8) ((x) >> 48); \
*((str) + 0) = (uint8) ((x) >> 56); \
}
#define PACK64(str, x) \
{ \
*(x) = ((uint64) *((str) + 7) ) \
| ((uint64) *((str) + 6) << 8) \
| ((uint64) *((str) + 5) << 16) \
| ((uint64) *((str) + 4) << 24) \
| ((uint64) *((str) + 3) << 32) \
| ((uint64) *((str) + 2) << 40) \
| ((uint64) *((str) + 1) << 48) \
| ((uint64) *((str) + 0) << 56); \
}
/* Macros used for loops unrolling */
#define SHA256_SCR(i) \
{ \
w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \
+ SHA256_F3(w[i - 15]) + w[i - 16]; \
}
#define SHA512_SCR(i) \
{ \
w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \
+ SHA512_F3(w[i - 15]) + w[i - 16]; \
}
#define SHA256_EXP(a, b, c, d, e, f, g, h, j) \
{ \
t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \
+ sha256_k[j] + w[j]; \
t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \
wv[d] += t1; \
wv[h] = t1 + t2; \
}
#define SHA512_EXP(a, b, c, d, e, f, g ,h, j) \
{ \
t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \
+ sha512_k[j] + w[j]; \
t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \
wv[d] += t1; \
wv[h] = t1 + t2; \
}
namespace Firebird {
sha2_base::uint32 sha224_h0[8] =
{0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4};
sha2_base::uint32 sha256_h0[8] =
{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
sha2_base::uint64 sha384_h0[8] =
{0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL,
0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL,
0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL,
0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL};
sha2_base::uint64 sha512_h0[8] =
{0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL};
sha2_base::uint32 sha256_k[64] =
{0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
sha2_base::uint64 sha512_k[80] =
{0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};
/* sha2_base */
void sha2_base::getHash(unsigned char *digest)
{
sha_final(digest);
reset();
};
#ifndef NIST_COMPLIANCY_TESTS
void sha2_base::getHash(UCharBuffer& h)
{
sha_final(h.getBuffer(get_DigestSize()));
reset();
};
#endif
/* SHA-256 functions */
sha256::sha256() : sha2_base()
{
sha256_init(&ctx);
}
void sha256::sha256_transf(sha256_ctx * ctx, const unsigned char *message,
unsigned int block_nb)
{
uint32 w[64];
uint32 wv[8];
uint32 t1, t2;
const unsigned char *sub_block;
int i;
#ifndef UNROLL_LOOPS
int j;
#endif
for (i = 0; i < (int) block_nb; i++) {
sub_block = message + (i << 6);
#ifndef UNROLL_LOOPS
for (j = 0; j < 16; j++) {
PACK32(&sub_block[j << 2], &w[j]);
}
for (j = 16; j < 64; j++) {
SHA256_SCR(j);
}
for (j = 0; j < 8; j++) {
wv[j] = ctx->h[j];
}
for (j = 0; j < 64; j++) {
t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
+ sha256_k[j] + w[j];
t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
wv[7] = wv[6];
wv[6] = wv[5];
wv[5] = wv[4];
wv[4] = wv[3] + t1;
wv[3] = wv[2];
wv[2] = wv[1];
wv[1] = wv[0];
wv[0] = t1 + t2;
}
for (j = 0; j < 8; j++) {
ctx->h[j] += wv[j];
}
#else
PACK32(&sub_block[ 0], &w[ 0]); PACK32(&sub_block[ 4], &w[ 1]);
PACK32(&sub_block[ 8], &w[ 2]); PACK32(&sub_block[12], &w[ 3]);
PACK32(&sub_block[16], &w[ 4]); PACK32(&sub_block[20], &w[ 5]);
PACK32(&sub_block[24], &w[ 6]); PACK32(&sub_block[28], &w[ 7]);
PACK32(&sub_block[32], &w[ 8]); PACK32(&sub_block[36], &w[ 9]);
PACK32(&sub_block[40], &w[10]); PACK32(&sub_block[44], &w[11]);
PACK32(&sub_block[48], &w[12]); PACK32(&sub_block[52], &w[13]);
PACK32(&sub_block[56], &w[14]); PACK32(&sub_block[60], &w[15]);
SHA256_SCR(16); SHA256_SCR(17); SHA256_SCR(18); SHA256_SCR(19);
SHA256_SCR(20); SHA256_SCR(21); SHA256_SCR(22); SHA256_SCR(23);
SHA256_SCR(24); SHA256_SCR(25); SHA256_SCR(26); SHA256_SCR(27);
SHA256_SCR(28); SHA256_SCR(29); SHA256_SCR(30); SHA256_SCR(31);
SHA256_SCR(32); SHA256_SCR(33); SHA256_SCR(34); SHA256_SCR(35);
SHA256_SCR(36); SHA256_SCR(37); SHA256_SCR(38); SHA256_SCR(39);
SHA256_SCR(40); SHA256_SCR(41); SHA256_SCR(42); SHA256_SCR(43);
SHA256_SCR(44); SHA256_SCR(45); SHA256_SCR(46); SHA256_SCR(47);
SHA256_SCR(48); SHA256_SCR(49); SHA256_SCR(50); SHA256_SCR(51);
SHA256_SCR(52); SHA256_SCR(53); SHA256_SCR(54); SHA256_SCR(55);
SHA256_SCR(56); SHA256_SCR(57); SHA256_SCR(58); SHA256_SCR(59);
SHA256_SCR(60); SHA256_SCR(61); SHA256_SCR(62); SHA256_SCR(63);
wv[0] = ctx->h[0]; wv[1] = ctx->h[1];
wv[2] = ctx->h[2]; wv[3] = ctx->h[3];
wv[4] = ctx->h[4]; wv[5] = ctx->h[5];
wv[6] = ctx->h[6]; wv[7] = ctx->h[7];
SHA256_EXP(0,1,2,3,4,5,6,7, 0); SHA256_EXP(7,0,1,2,3,4,5,6, 1);
SHA256_EXP(6,7,0,1,2,3,4,5, 2); SHA256_EXP(5,6,7,0,1,2,3,4, 3);
SHA256_EXP(4,5,6,7,0,1,2,3, 4); SHA256_EXP(3,4,5,6,7,0,1,2, 5);
SHA256_EXP(2,3,4,5,6,7,0,1, 6); SHA256_EXP(1,2,3,4,5,6,7,0, 7);
SHA256_EXP(0,1,2,3,4,5,6,7, 8); SHA256_EXP(7,0,1,2,3,4,5,6, 9);
SHA256_EXP(6,7,0,1,2,3,4,5,10); SHA256_EXP(5,6,7,0,1,2,3,4,11);
SHA256_EXP(4,5,6,7,0,1,2,3,12); SHA256_EXP(3,4,5,6,7,0,1,2,13);
SHA256_EXP(2,3,4,5,6,7,0,1,14); SHA256_EXP(1,2,3,4,5,6,7,0,15);
SHA256_EXP(0,1,2,3,4,5,6,7,16); SHA256_EXP(7,0,1,2,3,4,5,6,17);
SHA256_EXP(6,7,0,1,2,3,4,5,18); SHA256_EXP(5,6,7,0,1,2,3,4,19);
SHA256_EXP(4,5,6,7,0,1,2,3,20); SHA256_EXP(3,4,5,6,7,0,1,2,21);
SHA256_EXP(2,3,4,5,6,7,0,1,22); SHA256_EXP(1,2,3,4,5,6,7,0,23);
SHA256_EXP(0,1,2,3,4,5,6,7,24); SHA256_EXP(7,0,1,2,3,4,5,6,25);
SHA256_EXP(6,7,0,1,2,3,4,5,26); SHA256_EXP(5,6,7,0,1,2,3,4,27);
SHA256_EXP(4,5,6,7,0,1,2,3,28); SHA256_EXP(3,4,5,6,7,0,1,2,29);
SHA256_EXP(2,3,4,5,6,7,0,1,30); SHA256_EXP(1,2,3,4,5,6,7,0,31);
SHA256_EXP(0,1,2,3,4,5,6,7,32); SHA256_EXP(7,0,1,2,3,4,5,6,33);
SHA256_EXP(6,7,0,1,2,3,4,5,34); SHA256_EXP(5,6,7,0,1,2,3,4,35);
SHA256_EXP(4,5,6,7,0,1,2,3,36); SHA256_EXP(3,4,5,6,7,0,1,2,37);
SHA256_EXP(2,3,4,5,6,7,0,1,38); SHA256_EXP(1,2,3,4,5,6,7,0,39);
SHA256_EXP(0,1,2,3,4,5,6,7,40); SHA256_EXP(7,0,1,2,3,4,5,6,41);
SHA256_EXP(6,7,0,1,2,3,4,5,42); SHA256_EXP(5,6,7,0,1,2,3,4,43);
SHA256_EXP(4,5,6,7,0,1,2,3,44); SHA256_EXP(3,4,5,6,7,0,1,2,45);
SHA256_EXP(2,3,4,5,6,7,0,1,46); SHA256_EXP(1,2,3,4,5,6,7,0,47);
SHA256_EXP(0,1,2,3,4,5,6,7,48); SHA256_EXP(7,0,1,2,3,4,5,6,49);
SHA256_EXP(6,7,0,1,2,3,4,5,50); SHA256_EXP(5,6,7,0,1,2,3,4,51);
SHA256_EXP(4,5,6,7,0,1,2,3,52); SHA256_EXP(3,4,5,6,7,0,1,2,53);
SHA256_EXP(2,3,4,5,6,7,0,1,54); SHA256_EXP(1,2,3,4,5,6,7,0,55);
SHA256_EXP(0,1,2,3,4,5,6,7,56); SHA256_EXP(7,0,1,2,3,4,5,6,57);
SHA256_EXP(6,7,0,1,2,3,4,5,58); SHA256_EXP(5,6,7,0,1,2,3,4,59);
SHA256_EXP(4,5,6,7,0,1,2,3,60); SHA256_EXP(3,4,5,6,7,0,1,2,61);
SHA256_EXP(2,3,4,5,6,7,0,1,62); SHA256_EXP(1,2,3,4,5,6,7,0,63);
ctx->h[0] += wv[0]; ctx->h[1] += wv[1];
ctx->h[2] += wv[2]; ctx->h[3] += wv[3];
ctx->h[4] += wv[4]; ctx->h[5] += wv[5];
ctx->h[6] += wv[6]; ctx->h[7] += wv[7];
#endif /* !UNROLL_LOOPS */
}
}
void sha256::sha256_init(sha256_ctx * ctx)
{
#ifndef UNROLL_LOOPS
int i;
for (i = 0; i < 8; i++) {
ctx->h[i] = sha256_h0[i];
}
#else
ctx->h[0] = sha256_h0[0]; ctx->h[1] = sha256_h0[1];
ctx->h[2] = sha256_h0[2]; ctx->h[3] = sha256_h0[3];
ctx->h[4] = sha256_h0[4]; ctx->h[5] = sha256_h0[5];
ctx->h[6] = sha256_h0[6]; ctx->h[7] = sha256_h0[7];
#endif /* !UNROLL_LOOPS */
ctx->len = 0;
ctx->tot_len = 0;
}
void sha256::sha256_update(sha256_ctx * ctx, const unsigned char *message,
unsigned int len)
{
unsigned int block_nb;
unsigned int new_len, rem_len, tmp_len;
const unsigned char *shifted_message;
tmp_len = SHA256_BLOCK_SIZE - ctx->len;
rem_len = len < tmp_len ? len : tmp_len;
memcpy(&ctx->block[ctx->len], message, rem_len);
if (ctx->len + len < SHA256_BLOCK_SIZE) {
ctx->len += len;
return;
}
new_len = len - rem_len;
block_nb = new_len / SHA256_BLOCK_SIZE;
shifted_message = message + rem_len;
sha256_transf(ctx, ctx->block, 1);
sha256_transf(ctx, shifted_message, block_nb);
rem_len = new_len % SHA256_BLOCK_SIZE;
memcpy(ctx->block, &shifted_message[block_nb << 6],
rem_len);
ctx->len = rem_len;
ctx->tot_len += (block_nb + 1) << 6;
}
void sha256::sha256_final(sha256_ctx * ctx, unsigned char *digest)
{
unsigned int block_nb;
unsigned int pm_len;
unsigned int len_b;
#ifndef UNROLL_LOOPS
int i;
#endif
block_nb = (1 + ((SHA256_BLOCK_SIZE - 9)
< (ctx->len % SHA256_BLOCK_SIZE)));
len_b = (ctx->tot_len + ctx->len) << 3;
pm_len = block_nb << 6;
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
UNPACK32(len_b, ctx->block + pm_len - 4);
sha256_transf(ctx, ctx->block, block_nb);
#ifndef UNROLL_LOOPS
for (i = 0 ; i < 8; i++) {
UNPACK32(ctx->h[i], &digest[i << 2]);
}
#else
UNPACK32(ctx->h[0], &digest[ 0]);
UNPACK32(ctx->h[1], &digest[ 4]);
UNPACK32(ctx->h[2], &digest[ 8]);
UNPACK32(ctx->h[3], &digest[12]);
UNPACK32(ctx->h[4], &digest[16]);
UNPACK32(ctx->h[5], &digest[20]);
UNPACK32(ctx->h[6], &digest[24]);
UNPACK32(ctx->h[7], &digest[28]);
#endif /* !UNROLL_LOOPS */
}
/* SHA-512 functions */
sha512::sha512() : sha2_base()
{
sha512_init(&ctx);
}
void sha512::sha512_transf(sha512_ctx *ctx, const unsigned char *message,
unsigned int block_nb)
{
uint64 w[80];
uint64 wv[8];
uint64 t1, t2;
const unsigned char *sub_block;
int i, j;
for (i = 0; i < (int) block_nb; i++) {
sub_block = message + (i << 7);
#ifndef UNROLL_LOOPS
for (j = 0; j < 16; j++) {
PACK64(&sub_block[j << 3], &w[j]);
}
for (j = 16; j < 80; j++) {
SHA512_SCR(j);
}
for (j = 0; j < 8; j++) {
wv[j] = ctx->h[j];
}
for (j = 0; j < 80; j++) {
t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
+ sha512_k[j] + w[j];
t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
wv[7] = wv[6];
wv[6] = wv[5];
wv[5] = wv[4];
wv[4] = wv[3] + t1;
wv[3] = wv[2];
wv[2] = wv[1];
wv[1] = wv[0];
wv[0] = t1 + t2;
}
for (j = 0; j < 8; j++) {
ctx->h[j] += wv[j];
}
#else
PACK64(&sub_block[ 0], &w[ 0]); PACK64(&sub_block[ 8], &w[ 1]);
PACK64(&sub_block[ 16], &w[ 2]); PACK64(&sub_block[ 24], &w[ 3]);
PACK64(&sub_block[ 32], &w[ 4]); PACK64(&sub_block[ 40], &w[ 5]);
PACK64(&sub_block[ 48], &w[ 6]); PACK64(&sub_block[ 56], &w[ 7]);
PACK64(&sub_block[ 64], &w[ 8]); PACK64(&sub_block[ 72], &w[ 9]);
PACK64(&sub_block[ 80], &w[10]); PACK64(&sub_block[ 88], &w[11]);
PACK64(&sub_block[ 96], &w[12]); PACK64(&sub_block[104], &w[13]);
PACK64(&sub_block[112], &w[14]); PACK64(&sub_block[120], &w[15]);
SHA512_SCR(16); SHA512_SCR(17); SHA512_SCR(18); SHA512_SCR(19);
SHA512_SCR(20); SHA512_SCR(21); SHA512_SCR(22); SHA512_SCR(23);
SHA512_SCR(24); SHA512_SCR(25); SHA512_SCR(26); SHA512_SCR(27);
SHA512_SCR(28); SHA512_SCR(29); SHA512_SCR(30); SHA512_SCR(31);
SHA512_SCR(32); SHA512_SCR(33); SHA512_SCR(34); SHA512_SCR(35);
SHA512_SCR(36); SHA512_SCR(37); SHA512_SCR(38); SHA512_SCR(39);
SHA512_SCR(40); SHA512_SCR(41); SHA512_SCR(42); SHA512_SCR(43);
SHA512_SCR(44); SHA512_SCR(45); SHA512_SCR(46); SHA512_SCR(47);
SHA512_SCR(48); SHA512_SCR(49); SHA512_SCR(50); SHA512_SCR(51);
SHA512_SCR(52); SHA512_SCR(53); SHA512_SCR(54); SHA512_SCR(55);
SHA512_SCR(56); SHA512_SCR(57); SHA512_SCR(58); SHA512_SCR(59);
SHA512_SCR(60); SHA512_SCR(61); SHA512_SCR(62); SHA512_SCR(63);
SHA512_SCR(64); SHA512_SCR(65); SHA512_SCR(66); SHA512_SCR(67);
SHA512_SCR(68); SHA512_SCR(69); SHA512_SCR(70); SHA512_SCR(71);
SHA512_SCR(72); SHA512_SCR(73); SHA512_SCR(74); SHA512_SCR(75);
SHA512_SCR(76); SHA512_SCR(77); SHA512_SCR(78); SHA512_SCR(79);
wv[0] = ctx->h[0]; wv[1] = ctx->h[1];
wv[2] = ctx->h[2]; wv[3] = ctx->h[3];
wv[4] = ctx->h[4]; wv[5] = ctx->h[5];
wv[6] = ctx->h[6]; wv[7] = ctx->h[7];
j = 0;
do {
SHA512_EXP(0,1,2,3,4,5,6,7,j); j++;
SHA512_EXP(7,0,1,2,3,4,5,6,j); j++;
SHA512_EXP(6,7,0,1,2,3,4,5,j); j++;
SHA512_EXP(5,6,7,0,1,2,3,4,j); j++;
SHA512_EXP(4,5,6,7,0,1,2,3,j); j++;
SHA512_EXP(3,4,5,6,7,0,1,2,j); j++;
SHA512_EXP(2,3,4,5,6,7,0,1,j); j++;
SHA512_EXP(1,2,3,4,5,6,7,0,j); j++;
} while (j < 80);
ctx->h[0] += wv[0]; ctx->h[1] += wv[1];
ctx->h[2] += wv[2]; ctx->h[3] += wv[3];
ctx->h[4] += wv[4]; ctx->h[5] += wv[5];
ctx->h[6] += wv[6]; ctx->h[7] += wv[7];
#endif /* !UNROLL_LOOPS */
}
}
void sha512::sha512_init(sha512_ctx *ctx)
{
#ifndef UNROLL_LOOPS
int i;
for (i = 0; i < 8; i++) {
ctx->h[i] = sha512_h0[i];
}
#else
ctx->h[0] = sha512_h0[0]; ctx->h[1] = sha512_h0[1];
ctx->h[2] = sha512_h0[2]; ctx->h[3] = sha512_h0[3];
ctx->h[4] = sha512_h0[4]; ctx->h[5] = sha512_h0[5];
ctx->h[6] = sha512_h0[6]; ctx->h[7] = sha512_h0[7];
#endif /* !UNROLL_LOOPS */
ctx->len = 0;
ctx->tot_len = 0;
}
void sha512::sha512_update(sha512_ctx *ctx, const unsigned char *message,
unsigned int len)
{
unsigned int block_nb;
unsigned int new_len, rem_len, tmp_len;
const unsigned char *shifted_message;
tmp_len = SHA512_BLOCK_SIZE - ctx->len;
rem_len = len < tmp_len ? len : tmp_len;
memcpy(&ctx->block[ctx->len], message, rem_len);
if (ctx->len + len < SHA512_BLOCK_SIZE) {
ctx->len += len;
return;
}
new_len = len - rem_len;
block_nb = new_len / SHA512_BLOCK_SIZE;
shifted_message = message + rem_len;
sha512_transf(ctx, ctx->block, 1);
sha512_transf(ctx, shifted_message, block_nb);
rem_len = new_len % SHA512_BLOCK_SIZE;
memcpy(ctx->block, &shifted_message[block_nb << 7],
rem_len);
ctx->len = rem_len;
ctx->tot_len += (block_nb + 1) << 7;
}
void sha512::sha512_final(sha512_ctx *ctx, unsigned char *digest)
{
unsigned int block_nb;
unsigned int pm_len;
unsigned int len_b;
#ifndef UNROLL_LOOPS
int i;
#endif
block_nb = 1 + ((SHA512_BLOCK_SIZE - 17)
< (ctx->len % SHA512_BLOCK_SIZE));
len_b = (ctx->tot_len + ctx->len) << 3;
pm_len = block_nb << 7;
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
UNPACK32(len_b, ctx->block + pm_len - 4);
sha512_transf(ctx, ctx->block, block_nb);
#ifndef UNROLL_LOOPS
for (i = 0 ; i < 8; i++) {
UNPACK64(ctx->h[i], &digest[i << 3]);
}
#else
UNPACK64(ctx->h[0], &digest[ 0]);
UNPACK64(ctx->h[1], &digest[ 8]);
UNPACK64(ctx->h[2], &digest[16]);
UNPACK64(ctx->h[3], &digest[24]);
UNPACK64(ctx->h[4], &digest[32]);
UNPACK64(ctx->h[5], &digest[40]);
UNPACK64(ctx->h[6], &digest[48]);
UNPACK64(ctx->h[7], &digest[56]);
#endif /* !UNROLL_LOOPS */
}
/* SHA-384 functions */
sha384::sha384() : sha512()
{
sha384_init(&ctx);
}
void sha384::sha384_init(sha384_ctx *ctx)
{
#ifndef UNROLL_LOOPS
int i;
for (i = 0; i < 8; i++) {
ctx->h[i] = sha384_h0[i];
}
#else
ctx->h[0] = sha384_h0[0]; ctx->h[1] = sha384_h0[1];
ctx->h[2] = sha384_h0[2]; ctx->h[3] = sha384_h0[3];
ctx->h[4] = sha384_h0[4]; ctx->h[5] = sha384_h0[5];
ctx->h[6] = sha384_h0[6]; ctx->h[7] = sha384_h0[7];
#endif /* !UNROLL_LOOPS */
ctx->len = 0;
ctx->tot_len = 0;
}
void sha384::sha384_update(sha384_ctx *ctx,const unsigned char *message,
unsigned int len)
{
unsigned int block_nb;
unsigned int new_len, rem_len, tmp_len;
const unsigned char *shifted_message;
tmp_len = SHA384_BLOCK_SIZE - ctx->len;
rem_len = len < tmp_len ? len : tmp_len;
memcpy(&ctx->block[ctx->len], message, rem_len);
if (ctx->len + len < SHA384_BLOCK_SIZE) {
ctx->len += len;
return;
}
new_len = len - rem_len;
block_nb = new_len / SHA384_BLOCK_SIZE;
shifted_message = message + rem_len;
sha512_transf(ctx, ctx->block, 1);
sha512_transf(ctx, shifted_message, block_nb);
rem_len = new_len % SHA384_BLOCK_SIZE;
memcpy(ctx->block, &shifted_message[block_nb << 7],
rem_len);
ctx->len = rem_len;
ctx->tot_len += (block_nb + 1) << 7;
}
void sha384::sha384_final(sha384_ctx *ctx, unsigned char *digest)
{
unsigned int block_nb;
unsigned int pm_len;
unsigned int len_b;
#ifndef UNROLL_LOOPS
int i;
#endif
block_nb = (1 + ((SHA384_BLOCK_SIZE - 17)
< (ctx->len % SHA384_BLOCK_SIZE)));
len_b = (ctx->tot_len + ctx->len) << 3;
pm_len = block_nb << 7;
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
UNPACK32(len_b, ctx->block + pm_len - 4);
sha512_transf(ctx, ctx->block, block_nb);
#ifndef UNROLL_LOOPS
for (i = 0 ; i < 6; i++) {
UNPACK64(ctx->h[i], &digest[i << 3]);
}
#else
UNPACK64(ctx->h[0], &digest[ 0]);
UNPACK64(ctx->h[1], &digest[ 8]);
UNPACK64(ctx->h[2], &digest[16]);
UNPACK64(ctx->h[3], &digest[24]);
UNPACK64(ctx->h[4], &digest[32]);
UNPACK64(ctx->h[5], &digest[40]);
#endif /* !UNROLL_LOOPS */
}
/* SHA-224 functions */
sha224::sha224() : sha256()
{
sha224_init(&ctx);
}
void sha224::sha224_init(sha224_ctx *ctx)
{
#ifndef UNROLL_LOOPS
int i;
for (i = 0; i < 8; i++) {
ctx->h[i] = sha224_h0[i];
}
#else
ctx->h[0] = sha224_h0[0]; ctx->h[1] = sha224_h0[1];
ctx->h[2] = sha224_h0[2]; ctx->h[3] = sha224_h0[3];
ctx->h[4] = sha224_h0[4]; ctx->h[5] = sha224_h0[5];
ctx->h[6] = sha224_h0[6]; ctx->h[7] = sha224_h0[7];
#endif /* !UNROLL_LOOPS */
ctx->len = 0;
ctx->tot_len = 0;
}
void sha224::sha224_update(sha224_ctx *ctx, const unsigned char *message,
unsigned int len)
{
unsigned int block_nb;
unsigned int new_len, rem_len, tmp_len;
const unsigned char *shifted_message;
tmp_len = SHA224_BLOCK_SIZE - ctx->len;
rem_len = len < tmp_len ? len : tmp_len;
memcpy(&ctx->block[ctx->len], message, rem_len);
if (ctx->len + len < SHA224_BLOCK_SIZE) {
ctx->len += len;
return;
}
new_len = len - rem_len;
block_nb = new_len / SHA224_BLOCK_SIZE;
shifted_message = message + rem_len;
sha256_transf(ctx,ctx->block, 1);
sha256_transf(ctx, shifted_message, block_nb);
rem_len = new_len % SHA224_BLOCK_SIZE;
memcpy(ctx->block, &shifted_message[block_nb << 6],
rem_len);
ctx->len = rem_len;
ctx->tot_len += (block_nb + 1) << 6;
}
void sha224::sha224_final(sha224_ctx *ctx, unsigned char *digest)
{
unsigned int block_nb;
unsigned int pm_len;
unsigned int len_b;
#ifndef UNROLL_LOOPS
int i;
#endif
block_nb = (1 + ((SHA224_BLOCK_SIZE - 9)
< (ctx->len % SHA224_BLOCK_SIZE)));
len_b = (ctx->tot_len + ctx->len) << 3;
pm_len = block_nb << 6;
memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
ctx->block[ctx->len] = 0x80;
UNPACK32(len_b, ctx->block + pm_len - 4);
sha256_transf(ctx, ctx->block, block_nb);
#ifndef UNROLL_LOOPS
for (i = 0 ; i < 7; i++) {
UNPACK32(ctx->h[i], &digest[i << 2]);
}
#else
UNPACK32(ctx->h[0], &digest[ 0]);
UNPACK32(ctx->h[1], &digest[ 4]);
UNPACK32(ctx->h[2], &digest[ 8]);
UNPACK32(ctx->h[3], &digest[12]);
UNPACK32(ctx->h[4], &digest[16]);
UNPACK32(ctx->h[5], &digest[20]);
UNPACK32(ctx->h[6], &digest[24]);
#endif /* !UNROLL_LOOPS */
}
} // namespace Firebird
#ifdef NIST_COMPLIANCY_TESTS
/* FIPS 180-2 Validation tests */
#include <stdio.h>
#include <stdlib.h>
void test(const char *vector, unsigned char *digest,
unsigned int digest_size)
{
char output[2 * SHA_MAX_DIGEST_SIZE + 1];
int i;
output[2 * digest_size] = '\0';
for (i = 0; i < (int) digest_size ; i++) {
sprintf(output + 2 * i, "%02x", digest[i]);
}
printf("H: %s\n", output);
if (strcmp(vector, output)) {
fprintf(stderr, "Test failed.\n");
exit(EXIT_FAILURE);
}
}
using namespace Firebird;
int main(void)
{
static const char *vectors[4][3] =
{ /* SHA-224 */
{
"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7",
"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525",
"20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67",
},
/* SHA-256 */
{
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1",
"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0",
},
/* SHA-384 */
{
"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed"
"8086072ba1e7cc2358baeca134c825a7",
"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712"
"fcc7c71a557e2db966c3e9fa91746039",
"9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b"
"07b8b3dc38ecc4ebae97ddd87f3d8985",
},
/* SHA-512 */
{
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a"
"2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018"
"501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909",
"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"
"de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"
}
};
static const char message1[] = "abc";
static const char message2a[] = "abcdbcdecdefdefgefghfghighijhi"
"jkijkljklmklmnlmnomnopnopq";
static const char message2b[] = "abcdefghbcdefghicdefghijdefghijkefghij"
"klfghijklmghijklmnhijklmnoijklmnopjklm"
"nopqklmnopqrlmnopqrsmnopqrstnopqrstu";
unsigned char *message3;
unsigned int message3_len = 1000000;
unsigned char digest[SHA512_DIGEST_SIZE];
message3 = (unsigned char *) malloc(message3_len);
if (message3 == NULL) {
fprintf(stderr, "Can't allocate memory\n");
return -1;
}
memset(message3, 'a', message3_len);
printf("SHA-2 FIPS 180-2 Validation tests\n\n");
printf("SHA-224 Test vectors\n");
get_digest<sha224>((const unsigned char *) message1, strlen(message1), digest);
test(vectors[0][0], digest, SHA224_DIGEST_SIZE);
get_digest<sha224>((const unsigned char *) message2a, strlen(message2a), digest);
test(vectors[0][1], digest, SHA224_DIGEST_SIZE);
get_digest<sha224>(message3, message3_len, digest);
test(vectors[0][2], digest, SHA224_DIGEST_SIZE);
printf("\n");
printf("SHA-256 Test vectors\n");
get_digest<sha256>((const unsigned char *) message1, strlen(message1), digest);
test(vectors[1][0], digest, SHA256_DIGEST_SIZE);
get_digest<sha256>((const unsigned char *) message2a, strlen(message2a), digest);
test(vectors[1][1], digest, SHA256_DIGEST_SIZE);
get_digest<sha256>(message3, message3_len, digest);
test(vectors[1][2], digest, SHA256_DIGEST_SIZE);
printf("\n");
printf("SHA-384 Test vectors\n");
get_digest<sha384>((const unsigned char *) message1, strlen(message1), digest);
test(vectors[2][0], digest, SHA384_DIGEST_SIZE);
get_digest<sha384>((const unsigned char *)message2b, strlen(message2b), digest);
test(vectors[2][1], digest, SHA384_DIGEST_SIZE);
get_digest<sha384>(message3, message3_len, digest);
test(vectors[2][2], digest, SHA384_DIGEST_SIZE);
printf("\n");
printf("SHA-512 Test vectors\n");
get_digest<sha512>((const unsigned char *) message1, strlen(message1), digest);
test(vectors[3][0], digest, SHA512_DIGEST_SIZE);
get_digest<sha512>((const unsigned char *) message2b, strlen(message2b), digest);
test(vectors[3][1], digest, SHA512_DIGEST_SIZE);
get_digest<sha512>(message3, message3_len, digest);
test(vectors[3][2], digest, SHA512_DIGEST_SIZE);
printf("\n");
printf("All tests passed.\n");
return 0;
}
#endif /* TEST_VECTORS */

276
src/common/sha2/sha2.h Normal file
View File

@ -0,0 +1,276 @@
/*
* FIPS 180-2 SHA-224/256/384/512 implementation
* Last update: 02/02/2007
* Issue date: 04/30/2005
* https://github.com/ouah/sha2
*
* Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* Updated for use in Firebird by Tony Whyman <tony@mwasoftware.co.uk>
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* This update is intended to make available the SHA-2 family of message
* digests as C++ classes for use in Firebird. sha224, sha256, sha384 and
* sha512 are each implemented as separate classes. The class methods are
* intended to be as similar as possible to the legacy class sha1 in order
* to facilitate straightforward replacement.
*
* This implementation also comes with a NIST compliancy test for each
* digest. This is enabled by building with the NIST_COMPLIANCY_TESTS symbol
* defined.
*/
#ifndef _SHA2_H
#define _SHA2_H
#include <string>
#include <string.h>
#ifndef NIST_COMPLIANCY_TESTS
#include "firebird.h"
#include "../../common/classes/alloc.h"
#include "../../common/classes/array.h"
#include "../../common/classes/fb_string.h"
#include "../../common/utils_proto.h"
#endif
#define SHA224_DIGEST_SIZE ( 224 / 8)
#define SHA256_DIGEST_SIZE ( 256 / 8)
#define SHA384_DIGEST_SIZE ( 384 / 8)
#define SHA512_DIGEST_SIZE ( 512 / 8)
#define SHA_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
#define SHA256_BLOCK_SIZE ( 512 / 8)
#define SHA512_BLOCK_SIZE (1024 / 8)
#define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE
#define SHA224_BLOCK_SIZE SHA256_BLOCK_SIZE
namespace Firebird {
/* This template function provides a simple one line means of computing a SHA-2
* digest from an arbitrary length message.
*/
template<class SHA>void get_digest(const unsigned char *message, size_t len, unsigned char *digest)
{
SHA sha;
sha.process(len, message);
sha.getHash(digest);
}
#ifndef NIST_COMPLIANCY_TESTS
/* This template class provides a simple one line means of computing a SHA-2
* digest from an arbitrary length message, and encoding the result in BASE64.
*/
template<class SHA> void hashBased64(Firebird::string& hash, const Firebird::string& data)
{
SHA digest;
digest.process(data.length(), data.c_str());
UCharBuffer b;
digest.getHash(b);
fb_utils::base64(hash, b);
}
/* The sha2_base class is an abstract class that is the ancestor for all
* the SHA-2 classes. It defines all public methods for the classes and
* a common model of use.
*
* When instatiated a SHA-2 class is already initialized for use. The message
* for which a digest is required is then fed to the class using one of
* the "process" methods, either as a single action or accumulatively.
*
* When the entire message has been input, the resulting digest is returned
* by a "getHash" method. Calling "getHash" also clears the digest and
* re-initializes the SHA-2 generator ready to compute a new digest.
*
* A SHA-2 generator can be cleared down and re-initialized at any time
* by calling the "reset" method.
*/
class sha2_base : public GlobalStorage {
#else
class sha2_base {
#endif
public:
sha2_base() {};
virtual ~sha2_base() {};
virtual const unsigned int get_DigestSize()=0;
virtual const unsigned int get_BlockSize()=0;
typedef unsigned char uint8;
typedef unsigned int uint32;
typedef unsigned long long uint64;
protected:
virtual void sha_init() {};
virtual void sha_update(const unsigned char *message, unsigned int len)=0;
virtual void sha_final(unsigned char *digest)=0;
public:
void reset() {sha_init();};
void process(size_t length, const void* bytes)
{
sha_update(static_cast<const unsigned char*>(bytes), length);
}
void process(size_t length, const unsigned char* message)
{
sha_update(message, length);
}
void process(const std::string& str)
{
process(str.length(), str.c_str());
}
void process(const char* str)
{
process(strlen(str), str);
}
void getHash(unsigned char *digest);
#ifndef NIST_COMPLIANCY_TESTS
void process(const UCharBuffer& bytes)
{
process(bytes.getCount(), bytes.begin());
}
void getHash(UCharBuffer& h);
#endif
};
class sha256 : public sha2_base {
public:
sha256();
const unsigned int get_DigestSize() {return SHA256_DIGEST_SIZE;};
const unsigned int get_BlockSize() {return SHA256_BLOCK_SIZE;};
protected:
typedef struct {
unsigned int tot_len;
unsigned int len;
unsigned char block[2 * SHA256_BLOCK_SIZE];
uint32 h[8];
} sha256_ctx;
private:
void sha256_init(sha256_ctx * ctx);
void sha256_update(sha256_ctx *ctx, const unsigned char *message,
unsigned int len);
void sha256_final(sha256_ctx *ctx, unsigned char *digest);
protected:
sha256_ctx ctx;
void sha256_transf(sha256_ctx * ctx, const unsigned char *message,
unsigned int block_nb);
void sha_init() {sha256_init(&ctx);};
void sha_update(const unsigned char *message, unsigned int len) {sha256_update(&ctx,message,len);};
void sha_final(unsigned char *digest) {sha256_final(&ctx,digest);};
};
class sha224 : public sha256 {
public:
sha224();
const unsigned int get_DigestSize() {return SHA224_DIGEST_SIZE;};
const unsigned int get_BlockSize() {return SHA224_BLOCK_SIZE;};
private:
typedef sha256_ctx sha224_ctx;
void sha224_init(sha224_ctx *ctx);
void sha224_update(sha224_ctx *ctx, const unsigned char *message,
unsigned int len);
void sha224_final(sha224_ctx *ctx, unsigned char *digest);
protected:
void sha_init() {sha224_init(&ctx);};
void sha_update(const unsigned char *message, unsigned int len) {sha224_update(&ctx, message, len);};
void sha_final(unsigned char *digest) {sha224_final(&ctx,digest);};
};
class sha512 : public sha2_base {
public:
sha512();
const unsigned int get_DigestSize() {return SHA512_DIGEST_SIZE;};
const unsigned int get_BlockSize() {return SHA512_BLOCK_SIZE;};
protected:
typedef struct {
unsigned int tot_len;
unsigned int len;
unsigned char block[2 * SHA512_BLOCK_SIZE];
uint64 h[8];
} sha512_ctx;
private:
void sha512_init(sha512_ctx *ctx);
void sha512_update(sha512_ctx *ctx, const unsigned char *message,
unsigned int len);
void sha512_final(sha512_ctx *ctx, unsigned char *digest);
protected:
sha512_ctx ctx;
void sha512_transf(sha512_ctx *ctx, const unsigned char *message,
unsigned int block_nb);
void sha_init() {sha512_init(&ctx);};
void sha_update(const unsigned char *message, unsigned int len) {sha512_update(&ctx, message, len);};
void sha_final(unsigned char *digest) {sha512_final(&ctx, digest);};
};
class sha384 : public sha512 {
public:
sha384();
const unsigned int get_DigestSize() {return SHA384_DIGEST_SIZE;};
const unsigned int get_BlockSize() {return SHA384_BLOCK_SIZE;};
private:
typedef sha512_ctx sha384_ctx;
void sha384_init(sha384_ctx *ctx);
void sha384_update(sha384_ctx *ctx, const unsigned char *message,
unsigned int len);
void sha384_final(sha384_ctx *ctx, unsigned char *digest);
protected:
void sha_init() {sha384_init(&ctx);};
void sha_update(const unsigned char *message, unsigned int len) {sha384_update(&ctx,message,len);};
void sha_final(unsigned char *digest) {sha384_final(&ctx, digest);};
};
} //Firebird
#endif /* !_SHA2_H */