| /* ========================================================================= |
| * $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 */ |