mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
OcCryptoLib: Import secure memory comparison and password verification APIs
This commit is contained in:
parent
357142b6e9
commit
d1c565a246
@ -305,4 +305,55 @@ Sha384 (
|
||||
UINTN Len
|
||||
);
|
||||
|
||||
/**
|
||||
Performs a cryptographically secure comparison of the contents of two
|
||||
buffers.
|
||||
|
||||
This function compares Length bytes of SourceBuffer to Length bytes of
|
||||
DestinationBuffer in a cryptographically secure fashion. This especially
|
||||
implies that different lengths of the longest shared prefix do not change
|
||||
execution time in a way relevant to security.
|
||||
|
||||
If Length > 0 and DestinationBuffer is NULL, then ASSERT().
|
||||
If Length > 0 and SourceBuffer is NULL, then ASSERT().
|
||||
If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then ASSERT().
|
||||
If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then ASSERT().
|
||||
|
||||
@param DestinationBuffer The pointer to the destination buffer to compare.
|
||||
@param SourceBuffer The pointer to the source buffer to compare.
|
||||
@param Length The number of bytes to compare.
|
||||
|
||||
@return 0 All Length bytes of the two buffers are identical.
|
||||
@retval -1 The two buffers are not identical within Length
|
||||
bytes.
|
||||
**/
|
||||
INTN
|
||||
SecureCompareMem (
|
||||
IN CONST VOID *DestinationBuffer,
|
||||
IN CONST VOID *SourceBuffer,
|
||||
IN UINTN Length
|
||||
);
|
||||
|
||||
/**
|
||||
Verify Password and Salt against RefHash. The used hash function is SHA-512,
|
||||
thus the caller must ensure RefHash is at least 64 bytes in size.
|
||||
|
||||
@param[in] Password The entered password to verify.
|
||||
@param[in] PasswordSize The size, in bytes, of Password.
|
||||
@param[in] Salt The cryptographic salt appended to Password on hash.
|
||||
@param[in] SaltSize The size, in bytes, of Salt.
|
||||
@param[in] RefHash The SHA-512 hash of the reference password and Salt.
|
||||
|
||||
@returns Whether Password and Salt cryptographically match RefHash.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
OcVerifyPasswordSha512 (
|
||||
IN CONST UINT8 *Password,
|
||||
IN UINT32 PasswordSize,
|
||||
IN CONST UINT8 *Salt,
|
||||
IN UINT32 SaltSize,
|
||||
IN CONST UINT8 *RefHash
|
||||
);
|
||||
|
||||
#endif // OC_CRYPTO_LIB_H
|
||||
|
||||
@ -34,6 +34,8 @@
|
||||
Md5.c
|
||||
Sha1.c
|
||||
Sha2.c
|
||||
SecureMem.c
|
||||
PasswordHash.c
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
|
||||
108
Library/OcCryptoLib/PasswordHash.c
Normal file
108
Library/OcCryptoLib/PasswordHash.c
Normal file
@ -0,0 +1,108 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, Download-Fritz. All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include <Base.h>
|
||||
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/OcGuardLib.h>
|
||||
#include <Library/OcCryptoLib.h>
|
||||
|
||||
VOID
|
||||
OcHashPasswordSha512 (
|
||||
IN CONST UINT8 *Password,
|
||||
IN UINT32 PasswordSize,
|
||||
IN CONST UINT8 *Salt,
|
||||
IN UINT32 SaltSize,
|
||||
OUT UINT8 *Hash
|
||||
)
|
||||
{
|
||||
UINT32 Index;
|
||||
SHA512_CONTEXT ShaContext;
|
||||
|
||||
ASSERT (Password != NULL);
|
||||
ASSERT (PasswordSize > 0);
|
||||
ASSERT (Hash != NULL);
|
||||
|
||||
Sha512Init (&ShaContext);
|
||||
Sha512Update (&ShaContext, Password, PasswordSize);
|
||||
Sha512Update (&ShaContext, Salt, SaltSize);
|
||||
Sha512Final (&ShaContext, Hash);
|
||||
//
|
||||
// The hash function is applied iteratively to slow down bruteforce attacks.
|
||||
// The iteration count has been chosen to take roughly three seconds on
|
||||
// modern hardware.
|
||||
//
|
||||
for (Index = 0; Index < 5000000; ++Index) {
|
||||
Sha512Init (&ShaContext);
|
||||
Sha512Update (&ShaContext, Hash, SHA512_DIGEST_SIZE);
|
||||
//
|
||||
// Password and Salt are re-added into hashing to, in case of a hash
|
||||
// collision, again yield a unique hash in the subsequent iteration.
|
||||
//
|
||||
Sha512Update (&ShaContext, Password, PasswordSize);
|
||||
Sha512Update (&ShaContext, Salt, SaltSize);
|
||||
Sha512Final (&ShaContext, Hash);
|
||||
}
|
||||
//
|
||||
// The security-critical data constructed by this function is destroyed to
|
||||
// prevent data leakage by, after returning, free memory.
|
||||
// FIXME: ZeroMem() is not necessarily safe (it may be optimized away for
|
||||
// certain implementations) and CPU memory (registers and caches) are
|
||||
// not considered.
|
||||
//
|
||||
ZeroMem (&ShaContext, sizeof (ShaContext));
|
||||
}
|
||||
|
||||
/**
|
||||
Verify Password and Salt against RefHash. The used hash function is SHA-512,
|
||||
thus the caller must ensure RefHash is at least 64 bytes in size.
|
||||
|
||||
@param[in] Password The entered password to verify.
|
||||
@param[in] PasswordSize The size, in bytes, of Password.
|
||||
@param[in] Salt The cryptographic salt appended to Password on hash.
|
||||
@param[in] SaltSize The size, in bytes, of Salt.
|
||||
@param[in] RefHash The SHA-512 hash of the reference password and Salt.
|
||||
|
||||
@returns Whether Password and Salt cryptographically match RefHash.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
OcVerifyPasswordSha512 (
|
||||
IN CONST UINT8 *Password,
|
||||
IN UINT32 PasswordSize,
|
||||
IN CONST UINT8 *Salt,
|
||||
IN UINT32 SaltSize,
|
||||
IN CONST UINT8 *RefHash
|
||||
)
|
||||
{
|
||||
BOOLEAN Result;
|
||||
UINT8 VerifyHash[SHA512_DIGEST_SIZE];
|
||||
|
||||
ASSERT (Password != NULL);
|
||||
ASSERT (PasswordSize > 0);
|
||||
ASSERT (RefHash != NULL);
|
||||
|
||||
OcHashPasswordSha512 (Password, PasswordSize, Salt, SaltSize, VerifyHash);
|
||||
Result = SecureCompareMem (RefHash, VerifyHash, SHA512_DIGEST_SIZE) == 0;
|
||||
//
|
||||
// The security-critical data constructed by this function is destroyed to
|
||||
// prevent data leakage by, after returning, free memory.
|
||||
// FIXME: ZeroMem() is not necessarily safe (it may be optimized away for
|
||||
// certain implementations) and CPU memory (registers and caches) are
|
||||
// not considered.
|
||||
//
|
||||
ZeroMem (VerifyHash, SHA512_DIGEST_SIZE);
|
||||
|
||||
return Result;
|
||||
}
|
||||
93
Library/OcCryptoLib/SecureMem.c
Normal file
93
Library/OcCryptoLib/SecureMem.c
Normal file
@ -0,0 +1,93 @@
|
||||
/** @file
|
||||
Copyright (C) 2019, Download-Fritz. All rights reserved.
|
||||
|
||||
This program and the accompanying materials
|
||||
are licensed and made available under the terms and conditions of the BSD License
|
||||
which accompanies this distribution. The full text of the license may be found at
|
||||
http://opensource.org/licenses/bsd-license.php
|
||||
|
||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
|
||||
**/
|
||||
|
||||
#include <Base.h>
|
||||
|
||||
#include <Library/DebugLib.h>
|
||||
|
||||
/**
|
||||
Performs a cryptographically secure comparison of the contents of two
|
||||
buffers.
|
||||
|
||||
This function compares Length bytes of SourceBuffer to Length bytes of
|
||||
DestinationBuffer in a cryptographically secure fashion. This especially
|
||||
implies that different lengths of the longest shared prefix do not change
|
||||
execution time in a way relevant to security.
|
||||
|
||||
If Length > 0 and DestinationBuffer is NULL, then ASSERT().
|
||||
If Length > 0 and SourceBuffer is NULL, then ASSERT().
|
||||
If Length is greater than (MAX_ADDRESS - DestinationBuffer + 1), then ASSERT().
|
||||
If Length is greater than (MAX_ADDRESS - SourceBuffer + 1), then ASSERT().
|
||||
|
||||
@param DestinationBuffer The pointer to the destination buffer to compare.
|
||||
@param SourceBuffer The pointer to the source buffer to compare.
|
||||
@param Length The number of bytes to compare.
|
||||
|
||||
@return 0 All Length bytes of the two buffers are identical.
|
||||
@retval -1 The two buffers are not identical within Length
|
||||
bytes.
|
||||
**/
|
||||
INTN
|
||||
SecureCompareMem (
|
||||
IN CONST VOID *DestinationBuffer,
|
||||
IN CONST VOID *SourceBuffer,
|
||||
IN UINTN Length
|
||||
)
|
||||
{
|
||||
//
|
||||
// Based on libsodium secure_memcmp function implementation.
|
||||
//
|
||||
UINTN Index;
|
||||
//
|
||||
// The loop variables are volatile to prevent compiler optimizations, such as
|
||||
// security-hurting simplifications and intrinsics insertion.
|
||||
//
|
||||
volatile CONST UINT8 *volatile Destination;
|
||||
volatile CONST UINT8 *volatile Source;
|
||||
volatile UINT8 XorDiff;
|
||||
|
||||
if (Length > 0) {
|
||||
ASSERT (DestinationBuffer != NULL);
|
||||
ASSERT (SourceBuffer != NULL);
|
||||
ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)DestinationBuffer));
|
||||
ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)SourceBuffer));
|
||||
}
|
||||
|
||||
Destination = (volatile CONST UINT8 *)DestinationBuffer;
|
||||
Source = (volatile CONST UINT8 *)SourceBuffer;
|
||||
|
||||
XorDiff = 0;
|
||||
for (Index = 0; Index < Length; ++Index) {
|
||||
//
|
||||
// XOR is used to prevent comparison result based branches causing
|
||||
// slightly different execution times. A XOR operation only yields 0 when
|
||||
// both operands are equal.
|
||||
// Do not break early on mismatch to not leak information about prefixes.
|
||||
// The AND operation with 0xFFU is performed to have a result promotion to
|
||||
// unsigned int rather than int to ensure a safe cast.
|
||||
//
|
||||
XorDiff |= (UINT8)((Destination[Index] ^ (Source[Index])) & 0xFFU);
|
||||
}
|
||||
//
|
||||
// This is implemented as an arithmetic operation to have an uniform
|
||||
// execution time for success and failure cases.
|
||||
//
|
||||
// For XorDiff = 0, the subtraction wraps around and leads to a value of
|
||||
// UINT_MAX. All other values, as XorDiff is unsigned, must be greater than 0
|
||||
// and hence cannot wrap around. This means extracting bit 8 of the
|
||||
// operation's result will always yield 1 for XorDiff = 0 and always yield 0
|
||||
// for XorDiff != 0. This is then cast to INTN, which is safe because it
|
||||
// can only ever be 0 or 1, to finally yield the appropiate return value.
|
||||
//
|
||||
return ((INTN)(1U & ((XorDiff - 1U) >> 8U))) - 1;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user