📄 sps_dve.c
字号:
/** * @file sps_dve.c * SPS module for decryption and signature verfication * (dve = decryption and verification engine :-) * * @version $Revision$ $State$ * * @date @(#) Sep 30 2004, 21:24:01 * * @author Reinhard Wobst * *****************************************************************************//* * Copyright 2002 ADVANCED MICRO DEVICES, INC. All Rights Reserved. * * This software and any related documentation (the "Materials") are the * confidential proprietary information of AMD. Unless otherwise provided * in an agreement specifically licensing the Materials, the Materials are * provided in confidence and may not to be used, distributed, modified, or * reproduced in whole or in part by any means. * * LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY * EXPRESS OR IMPLIED WARRANTY OF ANY KIND, INCLUDING BUT NOT LIMITED TO * WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT, TITLE, FITNESS FOR ANY * PARTICULAR PURPOSE, OR WARRANTIES ARISING FORM CONDUCT, COURSE OF * DEALING, OR USAGE OF TRADE. IN NO EVENT SHALL AMD OR ITS LICENSORS BE * LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, * DAMAGES FOR LOSS OF PROFITS, BUSINESS INTERRUPTION, OR LOSS OF * INFORMATION) ARISING OUT OF THE USE OF OR INABILITY TO USE THE * MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR * LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE * ABOVE LIMITATION MAY NOT APPLY TO YOU. * * AMD does not assume any responsibility for any errors which may appear * in the Materials nor any responsibility to support or update the * Materials. AMD retains the right to modify the Materials at any time, * without notice, and is not obligated to provide such modified Materials * to you. * * NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make * any further information, software, technical information, know-how, or * show-how available to you. * *//****************************************************************************** Defines and includes*****************************************************************************/#include "sec.h"#include "debug.h"/* standard interfaces */#include <string.h>#include <stdlib.h>#include <stdio.h>#if STANDALONE == 0 /* Firmware interfaces */#include "sec.h"#include "ssfif.h"#endif#include "conf.h"#include "dve_api.h"#include "modules.h"#include "debug.h"#ifdef MSDOS#include "bn.h"#include "aes_api.h"#include "sha1.h"#else#include "Bn/bn.h"#include "Aes/aes_api.h"#include "Sha/sha1.h"#endif/****************************************************************************** Data*****************************************************************************/static struct MY_WORKSPACE *wsp;static int key_select[NUMSIG];static int my_first;/****************************************************************************** local function declarations*****************************************************************************/static void dve_sigstore(unsigned char *header);static unsigned char *sps_compose(const unsigned char part[16]);/****************************************************************************** global interface*****************************************************************************//** * @brief initialize symmetric decryption/verification * * allocate SHA context, decrypt session key, set IV, compute round keys, * set my_first to 1 (used in dve_process()) * * @param iv initialization vector of length MY_BLOCKSIZE/8 * @param cipertext at least MY_HEADSIZE bytes of ciphertext - see * conf.h (not checked!) * @param workspace pointer to workspace structure */void dve_init(unsigned char *ciphertext, unsigned char *iv, struct MY_WORKSPACE *workspace){ unsigned char lociv[MY_KEYSIZE / 8], start; static unsigned char fixedkey[MY_KEYSIZE / 8]; const static unsigned char const_part[16] = { 'w', 'h', 'i', 't', 'e', 'h', 'o', 'r', 's', 'e', 'e', 'd', 'u', 'c', 'a', 't', }; int n, alt; DP0(("*** Initialization")); my_first = 1; wsp = workspace; memcpy(workspace->AesOfbDecryptIv, iv, MY_BLOCKSIZE / 8); /* initialize NUMSIG SHA1 instances and diversify them */ for (n = NUMSIG; n--;) { SHA1Init(wsp->sha1_ctx + n); start = n & 0xff; SHA1Update(wsp->sha1_ctx + n, &start, 1); } /* initialize symmetric OFB decryption */ for (alt = 0, n = MY_KEYSIZE / 8; n--;) alt |= iv[n]; if (!alt) for (n = MY_KEYSIZE / 8; n--;) fixedkey[n] = n & 0xff; memcpy(lociv, iv, sizeof(lociv)); /* initialise AES module with IV to decrypt Session Key */ decrypt_aes_init(alt ? sps_compose(const_part) : fixedkey, lociv, &(wsp->Rkeys)); /* decrypt SK from ESK */ decrypt_aes_ofb(ciphertext, MY_KEYSIZE / 8);#if SPS_VERBOSE == 1 DP0(("master key: ")); for (n = 0; n < MY_KEYSIZE / 8; ++n) DP0(("%02x", (alt ? sps_compose(const_part) : fixedkey)[n])); DP0(("\n")); DP0(("session key: ")); for (n = 0; n < MY_KEYSIZE / 8; ++n) DP0(("%02x", ciphertext[n])); DP0(("\n"));#endif /* reinitialise AES module with SK for further decryption operations */ decrypt_aes_init(ciphertext, workspace->AesOfbDecryptIv, &(wsp->Rkeys));}/* ------------------------------------------------------------------ *//** * @brief routine which decrypts a data field encrypted with AES_128_OFB * * On first call (recognized by non-zero value of file-global variable * my_first), NUMSIG signatures and the following byte (for public key * selection) are read and stored after decryption. They are returned, * you have to skip them "by hand"! (the offset is MY_HEADSIZE) * * Hash computation is done background. * * @param cipherplaintext [in,out] ciphertext buffer, will be * overwritten with plaintext * @param len [in ] # of bytes for in and output * * @return * MY_PARMERR len < MY_HEADSIZE on first call, * len <= 0 on some following call * number of decrypted bytes else * */int dve_process(unsigned char *cipherplaintext, int len, SpsIntegrCheckMode_t IntCheckMode){ int m, n, ret; DP0(("dve_process: %d bytes to decrypt", len)); /* store signatures and compute keyselect field */ if (my_first) { if (len < MY_HEADSIZE) return MY_PARMERR; my_first = 0; /* for snowmass secure boot the signatures will not be encrypted! */ if (IntCheckMode == SPS_ENCRYPT_SIGNED) { decrypt_aes_ofb(cipherplaintext + MY_SIGOFF, len - MY_SIGOFF); } /* we check, if the three alignment bytes are 0, as expected. * if not - we have a decrypt error */ m = cipherplaintext[MY_HEADSIZE - 3]; m += cipherplaintext[MY_HEADSIZE - 2]; m += cipherplaintext[MY_HEADSIZE - 1]; if (m != 0) { DP0(("dve_process: decrypt error %02x\n", m)); return MY_PARMERR; } /* store signatures and key select info in workspace */ /* starts @ session key offset */ dve_sigstore(cipherplaintext + MY_SIGOFF); /* for including key_sel in hash adapt following calculations as to leave key_sel for SHA1Update below... */ /* replace all MY_HEADSIZE with (MY_HEADSIZE-(sizeof(key_sel) + sizeof(align))) */ cipherplaintext += MY_HEADSIZE; len -= MY_HEADSIZE; /* set len to zero to avoid SHA1 processing below.... */ } else { if (len <= 0) return MY_PARMERR; /* for snowmass secure boot first hash then decrypt! */ if (IntCheckMode == SPS_ENCRYPT_SIGNED) { decrypt_aes_ofb(cipherplaintext, len); } } ret = len; /* the included SHA1 implementation destroys the buffer, so we have * to copy it and hash in portions */ /* this will not fire for the PatchInfo field as len is asigned zero above... */ while (len > 0) { n = sizeof(wsp->scratchbuf); if (len < sizeof(wsp->scratchbuf)) n = len; for (m = NUMSIG; m--;) { memcpy(wsp->scratchbuf, cipherplaintext, n); SHA1Update(wsp->sha1_ctx + m, wsp->scratchbuf, n); } /* for snowmass secure boot first hash then decrypt! */ /* todo mgrell: review/test this construct for different length for streaming capabilities!: */ /* in original hss AES"de"crypt was done on entire block, here we do it in scratchbuf size manner... */ if (IntCheckMode == SPS_SIGN_ENCRYPTED) { decrypt_aes_ofb(cipherplaintext, n); } cipherplaintext += n; len -= n; } return ret;}/* ------------------------------------------------------------------ *//** * @brief store NUMSIG signatures, compute key numbers * * The select byte after the signatures is used to compute the * field key_select[NUMSIG] that determines which public keys * are used for encryption (and which signatures have to be skipped; * these values of key_select[] are negative). * * Structure of the select_byte: * * Bit 0 1 2 3 4 5 6 7 * key0 key1 key2 exclude * * The key number 0...3 of key0 selects one key among keys 0...3, * key1 selects 4...7, and key2 selects 8...11. * If the 'exclude' bits are zero, all three fields are valid. * Otherwise, for values 1...3 the key0...key2 has to be skipped, * respectively. */static void dve_sigstore(unsigned char *header){ const unsigned char mask = 03; int n, select_byte; select_byte = header[NUMSIG * MY_SIGSIZE / 8]; for (n = 0; n < NUMSIG; ++n, select_byte >>= 2) { memcpy((wsp->sigbuf)[n], header + n * MY_SIGSIZE / 8, MY_SIGSIZE / 8); key_select[n] = (int) (select_byte & mask) + (n << 2); } /* check for deactivated field */ if (select_byte &= mask) key_select[select_byte - 1] = -1;}/* ------------------------------------------------------------------ *//** * @brief check signatures: compute final hashes, test against sigbuf * * @return * MY_SIGFAIL signature failed * MY_ERR some internal operation failed * MY_OK else */int dve_sigcheck(){ unsigned char cmpsig[MY_SIGSIZE / 8 + 1]; /* maybe, "...+1" is not necessary */ unsigned char hash1[MY_HASHSIZE / 8]; int n, len, signr, keynr, ret; BN_CTX *ctx; BIGNUM *mod, *bnsign, *pubex; ret = MY_OK; mod = NULL; bnsign = NULL; pubex = NULL; /* compute hash over decrypted text */ for (n = NUMSIG; n--;) SHA1Final(wsp->Hash[n], wsp->sha1_ctx + n);#if SPS_VERBOSE == 1 { int k; for (k = 0; k < NUMSIG; ++k) { DP0(("Hash %d:", k + 1)); for (n = 0; n < MY_HASHSIZE / 8; ++n) { DP0(("%02x ", wsp->Hash[k][n])); if (n % 10 == 9) DP0(("\n")); } DP0(("\n")); } }#endif /* create bignum context */ ctx = BN_CTX_new(); if (ctx == NULL) return MY_ERR; /* *** check signatures */ for (signr = 0; signr < NUMSIG; ++signr) { if ((keynr = key_select[signr]) < 0) continue; /* deselected field */ /* Cannabis part: hashhash */ SHA1Init(wsp->sha1_ctx); SHA1Update(wsp->sha1_ctx, wsp->Hash[signr], MY_HASHSIZE / 8); SHA1Final(hash1, wsp->sha1_ctx); bnsign = pubex = mod = NULL; /* convert modulus */ mod = BN_bin2bn(Modulus[keynr], sizeof(Modulus[keynr]), NULL); DP0(("modulus %d converted", keynr)); if (mod == NULL) { ret = MY_ERR; break; } /* convert public exponent */ pubex = BN_bin2bn(publicExponent[keynr], sizeof(publicExponent[keynr]), NULL); DP0(("public exponent %d converted", keynr)); if (pubex == NULL) { ret = MY_ERR; break; } /* convert signature */ bnsign = BN_bin2bn((wsp->sigbuf)[signr], MY_SIGSIZE / 8, NULL); if (bnsign == NULL) { ret = MY_ERR; break; } /* public encrypt */ BN_mod_exp(bnsign, bnsign, pubex, mod, ctx); len = BN_bn2bin(bnsign, cmpsig); if (memcmp (hash1, cmpsig + MY_SIGSIZE / 8 - 1 - MY_HASHSIZE / 8, MY_HASHSIZE / 8)) { ret = MY_SIGFAIL; break; } DP0(("--> signature %d verified successfully", signr)); BN_free(bnsign); BN_free(pubex); BN_free(mod); } BN_CTX_free(ctx); if (ret != MY_OK) { if (bnsign != NULL) BN_free(bnsign); if (pubex != NULL) BN_free(pubex); if (mod != NULL) BN_free(mod); } return ret;}/* ------------------------------------------------------------------ *//** * @brief provide workspace for bignum library * * @param requ_size size of block, can be at most sizeof(BIGNUM)*32 * where the macro TABLE_SIZE defined as 32 in * bn/bn_exp.c is used (dirty, but with least * code modification) */BIGNUM *sps_dve_get_valbuf(int requ_size){ if (requ_size <= sizeof(BIGNUM) * 32) { return &(wsp->bn_buf[0]); } SsfFatalError(1); return NULL; /* dummy, for supressing compiler warning only */}/* ------------------------------------------------------------------ *//** * @brief generate a 16 byte data array * * @param */unsigned char *sps_compose(const unsigned char part[16]){#ifdef PATCH_SYSTEM_WITH_TEST_KEYS#ifndef MSDOS#warning using test symmetric keys#endif static unsigned char mykey[16] = { 0x5f, 0x44, 0x3a, 0x23, 0x5c, 0xc7, 0x5a, 0xbb, 0xdf, 0xbc, 0x97, 0xf2, 0xa9, 0xef, 0xa9, 0x51 };#else#warning using secure symmetric keys unsigned char *p, *q; int n; static unsigned char mykey[16] = { 'i', 'o', 'n', 'S', 'c', 'h', 'i', 'm', 'm', 'e', 'l', 'b', 'i', 'l', 'd', 'g', }; for (n = 16, p = &mykey[0], q = (unsigned char *) &part[0]; n--;) { *p++ ^= *q++; }#endif#ifdef USE_TDDFW_ENVIRONMENT return get_key();#else return mykey;#endif}static const unsigned char localaeskeywhichisnotsecurehere[] = { 0x5f, 0x44, 0x3a, 0x23, 0x5c, 0xc7, 0x5a, 0xbb, 0xdf, 0xbc, 0x97, 0xf2, 0xa9, 0xef, 0xa9, 0x51};unsigned char *get_key(){ return (unsigned char *) localaeskeywhichisnotsecurehere;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -