blob: 997f753edf2203d512e31b793b6d750b3d928565 [file] [log] [blame]
/* =========================================================================
* $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.c $
* $Revision: #3 $
* $Date: 2010/09/28 $
* $Change: 1596182 $
*
* Synopsys Portability Library Software and documentation
* (hereinafter, "Software") is an Unsupported proprietary work of
* Synopsys, Inc. unless otherwise expressly agreed to in writing
* between Synopsys and you.
*
* The Software IS NOT an item of Licensed Software or Licensed Product
* under any End User Software License Agreement or Agreement for
* Licensed Product with Synopsys or any supplement thereto. You are
* permitted to use and redistribute this Software in source and binary
* forms, with or without modification, provided that redistributions
* of source code must retain this notice. You may not view, use,
* disclose, copy or distribute this file or any information contained
* herein except pursuant to this license grant from Synopsys. If you
* do not agree with this notice, including the disclaimer below, then
* you are not authorized to use the Software.
*
* THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
* BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
* SYNOPSYS 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.
* ========================================================================= */
#ifdef DWC_CRYPTOLIB
#ifndef CONFIG_MACH_IPMATE
#include "dwc_dh.h"
#include "dwc_modpow.h"
#ifdef DEBUG
/* This function prints out a buffer in the format described in the Association
* Model specification. */
static void dh_dump(char *str, void *_num, int len)
{
uint8_t *num = _num;
int i;
DWC_PRINTF("%s\n", str);
for (i = 0; i < len; i ++) {
DWC_PRINTF("%02x", num[i]);
if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
}
DWC_PRINTF("\n");
}
#else
#define dh_dump(_x...) do {; } while(0)
#endif
/* Constant g value */
static __u32 dh_g[] = {
0x02000000,
};
/* Constant p value */
static __u32 dh_p[] = {
0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
};
static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
{
uint8_t *in = _in;
uint8_t *out = _out;
int i;
for (i=0; i<len; i++) {
out[i] = in[len-1-i];
}
}
/* Computes the modular exponentiation (num^exp % mod). num, exp, and mod are
* big endian numbers of size len, in bytes. Each len value must be a multiple
* of 4. */
int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
void *exp, uint32_t exp_len,
void *mod, uint32_t mod_len,
void *out)
{
/* modpow() takes little endian numbers. AM uses big-endian. This
* function swaps bytes of numbers before passing onto modpow. */
int retval = 0;
uint32_t *result;
uint32_t *bignum_num = dwc_alloc(mem_ctx, num_len + 4);
uint32_t *bignum_exp = dwc_alloc(mem_ctx, exp_len + 4);
uint32_t *bignum_mod = dwc_alloc(mem_ctx, mod_len + 4);
dh_swap_bytes(num, &bignum_num[1], num_len);
bignum_num[0] = num_len / 4;
dh_swap_bytes(exp, &bignum_exp[1], exp_len);
bignum_exp[0] = exp_len / 4;
dh_swap_bytes(mod, &bignum_mod[1], mod_len);
bignum_mod[0] = mod_len / 4;
result = dwc_modpow(mem_ctx, bignum_num, bignum_exp, bignum_mod);
if (!result) {
retval = -1;
goto dh_modpow_nomem;
}
dh_swap_bytes(&result[1], out, result[0] * 4);
dwc_free(mem_ctx, result);
dh_modpow_nomem:
dwc_free(mem_ctx, bignum_num);
dwc_free(mem_ctx, bignum_exp);
dwc_free(mem_ctx, bignum_mod);
return retval;
}
int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
{
int retval;
uint8_t m3[385];
#ifndef DH_TEST_VECTORS
DWC_RANDOM_BYTES(exp, 32);
#endif
/* Compute the pkd */
if ((retval = dwc_dh_modpow(mem_ctx, dh_g, 4,
exp, 32,
dh_p, 384, pk))) {
return retval;
}
m3[384] = nd;
DWC_MEMCPY(&m3[0], pk, 384);
DWC_SHA256(m3, 385, hash);
dh_dump("PK", pk, 384);
dh_dump("SHA-256(M3)", hash, 32);
return 0;
}
int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
uint8_t *exp, int is_host,
char *dd, uint8_t *ck, uint8_t *kdk)
{
int retval;
uint8_t mv[784];
uint8_t sha_result[32];
uint8_t dhkey[384];
uint8_t shared_secret[384];
char *message;
uint32_t vd;
uint8_t *pk;
if (is_host) {
pk = pkd;
}
else {
pk = pkh;
}
if ((retval = dwc_dh_modpow(mem_ctx, pk, 384,
exp, 32,
dh_p, 384, shared_secret))) {
return retval;
}
dh_dump("Shared Secret", shared_secret, 384);
DWC_SHA256(shared_secret, 384, dhkey);
dh_dump("DHKEY", dhkey, 384);
DWC_MEMCPY(&mv[0], pkd, 384);
DWC_MEMCPY(&mv[384], pkh, 384);
DWC_MEMCPY(&mv[768], "displayed digest", 16);
dh_dump("MV", mv, 784);
DWC_SHA256(mv, 784, sha_result);
dh_dump("SHA-256(MV)", sha_result, 32);
dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
dh_swap_bytes(sha_result, &vd, 4);
#ifdef DEBUG
DWC_PRINTF("Vd (decimal) = %d\n", vd);
#endif
switch (nd) {
case 2:
vd = vd % 100;
DWC_SPRINTF(dd, "%02d", vd);
break;
case 3:
vd = vd % 1000;
DWC_SPRINTF(dd, "%03d", vd);
break;
case 4:
vd = vd % 10000;
DWC_SPRINTF(dd, "%04d", vd);
break;
}
#ifdef DEBUG
DWC_PRINTF("Display Digits: %s\n", dd);
#endif
message = "connection key";
DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
DWC_MEMCPY(ck, sha_result, 16);
message = "key derivation key";
DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
DWC_MEMCPY(kdk, sha_result, 32);
return 0;
}
#ifdef DH_TEST_VECTORS
static __u8 dh_a[] = {
0x44, 0x00, 0x51, 0xd6,
0xf0, 0xb5, 0x5e, 0xa9,
0x67, 0xab, 0x31, 0xc6,
0x8a, 0x8b, 0x5e, 0x37,
0xd9, 0x10, 0xda, 0xe0,
0xe2, 0xd4, 0x59, 0xa4,
0x86, 0x45, 0x9c, 0xaa,
0xdf, 0x36, 0x75, 0x16,
};
static __u8 dh_b[] = {
0x5d, 0xae, 0xc7, 0x86,
0x79, 0x80, 0xa3, 0x24,
0x8c, 0xe3, 0x57, 0x8f,
0xc7, 0x5f, 0x1b, 0x0f,
0x2d, 0xf8, 0x9d, 0x30,
0x6f, 0xa4, 0x52, 0xcd,
0xe0, 0x7a, 0x04, 0x8a,
0xde, 0xd9, 0x26, 0x56,
};
void dwc_run_dh_test_vectors(void *mem_ctx)
{
uint8_t pkd[384];
uint8_t pkh[384];
uint8_t hashd[32];
uint8_t hashh[32];
uint8_t ck[16];
uint8_t kdk[32];
char dd[5];
DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
/* compute the PKd and SHA-256(PKd || Nd) */
DWC_PRINTF("Computing PKd\n");
dwc_dh_pk(mem_ctx, 2, dh_a, pkd, hashd);
/* compute the PKd and SHA-256(PKh || Nd) */
DWC_PRINTF("Computing PKh\n");
dwc_dh_pk(mem_ctx, 2, dh_b, pkh, hashh);
/* compute the dhkey */
dwc_dh_derive_keys(mem_ctx, 2, pkh, pkd, dh_a, 0, dd, ck, kdk);
}
#endif /* DH_TEST_VECTORS */
#endif /* !CONFIG_MACH_IPMATE */
#endif /* DWC_CRYPTOLIB */