efi-boot-shim/PasswordCrypt.c
Peter Jones 1d39ada8cb Revert lots of Cryptlib updates.
OpenSSL changes quite a bit of the key validation, and most of the keys
I can find in the wild aren't marked as trusted by the new checker.

Intel noticed this too: https://github.com/vathpela/edk2/commit/f536d7c3ed
but instead of fixing the compatibility error, they switched their test
data to match the bug.

So that's pretty broken.

For now, I'm reverting OpenSSL 1.1.0e, because we need those certs in
the wild to work.

This reverts commit 513cbe2aea.
This reverts commit e9cc33d6f2.
This reverts commit 80d49f758e.
This reverts commit 9bc647e2b2.
This reverts commit ae75df6232.
This reverts commit e883479f35.
This reverts commit 97469449fd.
This reverts commit e39692647f.
This reverts commit 0f3dfc01e2.
This reverts commit 4da6ac8195.
This reverts commit d064bd7eef.
This reverts commit 9bc86cfd6f.
This reverts commit ab9a05a10f.

Signed-off-by: Peter Jones <pjones@redhat.com>
2017-08-31 15:13:58 -04:00

343 lines
7.8 KiB
C

#include <efi.h>
#include <efilib.h>
#include <Library/BaseCryptLib.h>
#include <openssl/sha.h>
#include <openssl/md5.h>
#include <openssl/des.h>
#include "PasswordCrypt.h"
#include "crypt_blowfish.h"
#define TRAD_DES_HASH_SIZE 13 /* (64/6+1) + (12/6) */
#define BSDI_DES_HASH_SIZE 20 /* (64/6+1) + (24/6) + 4 + 1 */
#define BLOWFISH_HASH_SIZE 31 /* 184/6+1 */
UINT16 get_hash_size (const UINT16 method)
{
switch (method) {
case TRADITIONAL_DES:
return TRAD_DES_HASH_SIZE;
case EXTEND_BSDI_DES:
return BSDI_DES_HASH_SIZE;
case MD5_BASED:
return MD5_DIGEST_LENGTH;
case SHA256_BASED:
return SHA256_DIGEST_LENGTH;
case SHA512_BASED:
return SHA512_DIGEST_LENGTH;
case BLOWFISH_BASED:
return BLOWFISH_HASH_SIZE;
}
return 0;
}
static EFI_STATUS trad_des_crypt (const char *key, const char *salt, UINT8 *hash)
{
char result[TRAD_DES_HASH_SIZE + 1];
char *ret;
ret = DES_fcrypt(key, salt, result);
if (ret) {
CopyMem(hash, result, TRAD_DES_HASH_SIZE);
return EFI_SUCCESS;
}
return EFI_UNSUPPORTED;
}
static const char md5_salt_prefix[] = "$1$";
static EFI_STATUS md5_crypt (const char *key, UINT32 key_len,
const char *salt, UINT32 salt_size,
UINT8 *hash)
{
MD5_CTX ctx, alt_ctx;
UINT8 alt_result[MD5_DIGEST_LENGTH];
UINTN cnt;
MD5_Init(&ctx);
MD5_Update(&ctx, key, key_len);
MD5_Update(&ctx, md5_salt_prefix, sizeof(md5_salt_prefix) - 1);
MD5_Update(&ctx, salt, salt_size);
MD5_Init(&alt_ctx);
MD5_Update(&alt_ctx, key, key_len);
MD5_Update(&alt_ctx, salt, salt_size);
MD5_Update(&alt_ctx, key, key_len);
MD5_Final(alt_result, &alt_ctx);
for (cnt = key_len; cnt > 16; cnt -= 16)
MD5_Update(&ctx, alt_result, 16);
MD5_Update(&ctx, alt_result, cnt);
*alt_result = '\0';
for (cnt = key_len; cnt > 0; cnt >>= 1) {
if ((cnt & 1) != 0) {
MD5_Update(&ctx, alt_result, 1);
} else {
MD5_Update(&ctx, key, 1);
}
}
MD5_Final(alt_result, &ctx);
for (cnt = 0; cnt < 1000; ++cnt) {
MD5_Init(&ctx);
if ((cnt & 1) != 0)
MD5_Update(&ctx, key, key_len);
else
MD5_Update(&ctx, alt_result, 16);
if (cnt % 3 != 0)
MD5_Update(&ctx, salt, salt_size);
if (cnt % 7 != 0)
MD5_Update(&ctx, key, key_len);
if ((cnt & 1) != 0)
MD5_Update(&ctx, alt_result, 16);
else
MD5_Update(&ctx, key, key_len);
MD5_Final(alt_result, &ctx);
}
CopyMem(hash, alt_result, MD5_DIGEST_LENGTH);
return EFI_SUCCESS;
}
static EFI_STATUS sha256_crypt (const char *key, UINT32 key_len,
const char *salt, UINT32 salt_size,
const UINT32 rounds, UINT8 *hash)
{
SHA256_CTX ctx, alt_ctx;
UINT8 alt_result[SHA256_DIGEST_SIZE];
UINT8 tmp_result[SHA256_DIGEST_SIZE];
UINT8 *cp, *p_bytes, *s_bytes;
UINTN cnt;
SHA256_Init(&ctx);
SHA256_Update(&ctx, key, key_len);
SHA256_Update(&ctx, salt, salt_size);
SHA256_Init(&alt_ctx);
SHA256_Update(&alt_ctx, key, key_len);
SHA256_Update(&alt_ctx, salt, salt_size);
SHA256_Update(&alt_ctx, key, key_len);
SHA256_Final(alt_result, &alt_ctx);
for (cnt = key_len; cnt > 32; cnt -= 32)
SHA256_Update(&ctx, alt_result, 32);
SHA256_Update(&ctx, alt_result, cnt);
for (cnt = key_len; cnt > 0; cnt >>= 1) {
if ((cnt & 1) != 0) {
SHA256_Update(&ctx, alt_result, 32);
} else {
SHA256_Update(&ctx, key, key_len);
}
}
SHA256_Final(alt_result, &ctx);
SHA256_Init(&alt_ctx);
for (cnt = 0; cnt < key_len; ++cnt)
SHA256_Update(&alt_ctx, key, key_len);
SHA256_Final(tmp_result, &alt_ctx);
cp = p_bytes = AllocatePool(key_len);
for (cnt = key_len; cnt >= 32; cnt -= 32) {
CopyMem(cp, tmp_result, 32);
cp += 32;
}
CopyMem(cp, tmp_result, cnt);
SHA256_Init(&alt_ctx);
for (cnt = 0; cnt < 16ul + alt_result[0]; ++cnt)
SHA256_Update(&alt_ctx, salt, salt_size);
SHA256_Final(tmp_result, &alt_ctx);
cp = s_bytes = AllocatePool(salt_size);
for (cnt = salt_size; cnt >= 32; cnt -= 32) {
CopyMem(cp, tmp_result, 32);
cp += 32;
}
CopyMem(cp, tmp_result, cnt);
for (cnt = 0; cnt < rounds; ++cnt) {
SHA256_Init(&ctx);
if ((cnt & 1) != 0)
SHA256_Update(&ctx, p_bytes, key_len);
else
SHA256_Update(&ctx, alt_result, 32);
if (cnt % 3 != 0)
SHA256_Update(&ctx, s_bytes, salt_size);
if (cnt % 7 != 0)
SHA256_Update(&ctx, p_bytes, key_len);
if ((cnt & 1) != 0)
SHA256_Update(&ctx, alt_result, 32);
else
SHA256_Update(&ctx, p_bytes, key_len);
SHA256_Final(alt_result, &ctx);
}
CopyMem(hash, alt_result, SHA256_DIGEST_SIZE);
FreePool(p_bytes);
FreePool(s_bytes);
return EFI_SUCCESS;
}
static EFI_STATUS sha512_crypt (const char *key, UINT32 key_len,
const char *salt, UINT32 salt_size,
const UINT32 rounds, UINT8 *hash)
{
SHA512_CTX ctx, alt_ctx;
UINT8 alt_result[SHA512_DIGEST_LENGTH];
UINT8 tmp_result[SHA512_DIGEST_LENGTH];
UINT8 *cp, *p_bytes, *s_bytes;
UINTN cnt;
SHA512_Init(&ctx);
SHA512_Update(&ctx, key, key_len);
SHA512_Update(&ctx, salt, salt_size);
SHA512_Init(&alt_ctx);
SHA512_Update(&alt_ctx, key, key_len);
SHA512_Update(&alt_ctx, salt, salt_size);
SHA512_Update(&alt_ctx, key, key_len);
SHA512_Final(alt_result, &alt_ctx);
for (cnt = key_len; cnt > 64; cnt -= 64)
SHA512_Update(&ctx, alt_result, 64);
SHA512_Update(&ctx, alt_result, cnt);
for (cnt = key_len; cnt > 0; cnt >>= 1) {
if ((cnt & 1) != 0) {
SHA512_Update(&ctx, alt_result, 64);
} else {
SHA512_Update(&ctx, key, key_len);
}
}
SHA512_Final(alt_result, &ctx);
SHA512_Init(&alt_ctx);
for (cnt = 0; cnt < key_len; ++cnt)
SHA512_Update(&alt_ctx, key, key_len);
SHA512_Final(tmp_result, &alt_ctx);
cp = p_bytes = AllocatePool(key_len);
for (cnt = key_len; cnt >= 64; cnt -= 64) {
CopyMem(cp, tmp_result, 64);
cp += 64;
}
CopyMem(cp, tmp_result, cnt);
SHA512_Init(&alt_ctx);
for (cnt = 0; cnt < 16ul + alt_result[0]; ++cnt)
SHA512_Update(&alt_ctx, salt, salt_size);
SHA512_Final(tmp_result, &alt_ctx);
cp = s_bytes = AllocatePool(salt_size);
for (cnt = salt_size; cnt >= 64; cnt -= 64) {
CopyMem(cp, tmp_result, 64);
cp += 64;
}
CopyMem(cp, tmp_result, cnt);
for (cnt = 0; cnt < rounds; ++cnt) {
SHA512_Init(&ctx);
if ((cnt & 1) != 0)
SHA512_Update(&ctx, p_bytes, key_len);
else
SHA512_Update(&ctx, alt_result, 64);
if (cnt % 3 != 0)
SHA512_Update(&ctx, s_bytes, salt_size);
if (cnt % 7 != 0)
SHA512_Update(&ctx, p_bytes, key_len);
if ((cnt & 1) != 0)
SHA512_Update(&ctx, alt_result, 64);
else
SHA512_Update(&ctx, p_bytes, key_len);
SHA512_Final(alt_result, &ctx);
}
CopyMem(hash, alt_result, SHA512_DIGEST_LENGTH);
FreePool(p_bytes);
FreePool(s_bytes);
return EFI_SUCCESS;
}
#define BF_RESULT_SIZE (7 + 22 + 31 + 1)
static EFI_STATUS blowfish_crypt (const char *key, const char *salt, UINT8 *hash)
{
char *retval, result[BF_RESULT_SIZE];
retval = crypt_blowfish_rn (key, salt, result, BF_RESULT_SIZE);
if (!retval)
return EFI_UNSUPPORTED;
CopyMem(hash, result + 7 + 22, BF_RESULT_SIZE);
return EFI_SUCCESS;
}
EFI_STATUS password_crypt (const char *password, UINT32 pw_length,
const PASSWORD_CRYPT *pw_crypt, UINT8 *hash)
{
EFI_STATUS status;
if (!pw_crypt)
return EFI_INVALID_PARAMETER;
switch (pw_crypt->method) {
case TRADITIONAL_DES:
status = trad_des_crypt (password, (char *)pw_crypt->salt, hash);
break;
case EXTEND_BSDI_DES:
status = EFI_UNSUPPORTED;
break;
case MD5_BASED:
status = md5_crypt (password, pw_length, (char *)pw_crypt->salt,
pw_crypt->salt_size, hash);
break;
case SHA256_BASED:
status = sha256_crypt(password, pw_length, (char *)pw_crypt->salt,
pw_crypt->salt_size, pw_crypt->iter_count,
hash);
break;
case SHA512_BASED:
status = sha512_crypt(password, pw_length, (char *)pw_crypt->salt,
pw_crypt->salt_size, pw_crypt->iter_count,
hash);
break;
case BLOWFISH_BASED:
if (pw_crypt->salt_size != (7 + 22 + 1)) {
status = EFI_INVALID_PARAMETER;
break;
}
status = blowfish_crypt(password, (char *)pw_crypt->salt, hash);
break;
default:
return EFI_INVALID_PARAMETER;
}
return status;
}