| /* ========================================================================= |
| * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_crypto.c $ |
| * $Revision: #5 $ |
| * $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. |
| * ========================================================================= */ |
| |
| /** @file |
| * This file contains the WUSB cryptographic routines. |
| */ |
| |
| #ifdef DWC_CRYPTOLIB |
| |
| #include "dwc_crypto.h" |
| #include "usb.h" |
| |
| #ifdef DEBUG |
| static inline void dump_bytes(char *name, uint8_t *bytes, int len) |
| { |
| int i; |
| DWC_PRINTF("%s: ", name); |
| for (i=0; i<len; i++) { |
| DWC_PRINTF("%02x ", bytes[i]); |
| } |
| DWC_PRINTF("\n"); |
| } |
| #else |
| #define dump_bytes(x...) |
| #endif |
| |
| /* Display a block */ |
| void show_block(const u8 *blk, const char *prefix, const char *suffix, int a) |
| { |
| #ifdef DWC_DEBUG_CRYPTO |
| int i, blksize = 16; |
| |
| DWC_DEBUG("%s", prefix); |
| |
| if (suffix == NULL) { |
| suffix = "\n"; |
| blksize = a; |
| } |
| |
| for (i = 0; i < blksize; i++) |
| DWC_PRINT("%02x%s", *blk++, ((i & 3) == 3) ? " " : " "); |
| DWC_PRINT(suffix); |
| #endif |
| } |
| |
| /** |
| * Encrypts an array of bytes using the AES encryption engine. |
| * If <code>dst</code> == <code>src</code>, then the bytes will be encrypted |
| * in-place. |
| * |
| * @return 0 on success, negative error code on error. |
| */ |
| int dwc_wusb_aes_encrypt(u8 *src, u8 *key, u8 *dst) |
| { |
| u8 block_t[16]; |
| DWC_MEMSET(block_t, 0, 16); |
| |
| return DWC_AES_CBC(src, 16, key, 16, block_t, dst); |
| } |
| |
| /** |
| * The CCM-MAC-FUNCTION described in section 6.5 of the WUSB spec. |
| * This function takes a data string and returns the encrypted CBC |
| * Counter-mode MIC. |
| * |
| * @param key The 128-bit symmetric key. |
| * @param nonce The CCM nonce. |
| * @param label The unique 14-byte ASCII text label. |
| * @param bytes The byte array to be encrypted. |
| * @param len Length of the byte array. |
| * @param result Byte array to receive the 8-byte encrypted MIC. |
| */ |
| void dwc_wusb_cmf(u8 *key, u8 *nonce, |
| char *label, u8 *bytes, int len, u8 *result) |
| { |
| u8 block_m[16]; |
| u8 block_x[16]; |
| u8 block_t[8]; |
| int idx, blkNum; |
| u16 la = (u16)(len + 14); |
| |
| /* Set the AES-128 key */ |
| //dwc_aes_setkey(tfm, key, 16); |
| |
| /* Fill block B0 from flags = 0x59, N, and l(m) = 0 */ |
| block_m[0] = 0x59; |
| for (idx = 0; idx < 13; idx++) |
| block_m[idx + 1] = nonce[idx]; |
| block_m[14] = 0; |
| block_m[15] = 0; |
| |
| /* Produce the CBC IV */ |
| dwc_wusb_aes_encrypt(block_m, key, block_x); |
| show_block(block_m, "CBC IV in: ", "\n", 0); |
| show_block(block_x, "CBC IV out:", "\n", 0); |
| |
| /* Fill block B1 from l(a) = Blen + 14, and A */ |
| block_x[0] ^= (u8)(la >> 8); |
| block_x[1] ^= (u8)la; |
| for (idx = 0; idx < 14; idx++) |
| block_x[idx + 2] ^= label[idx]; |
| show_block(block_x, "After xor: ", "b1\n", 16); |
| |
| dwc_wusb_aes_encrypt(block_x, key, block_x); |
| show_block(block_x, "After AES: ", "b1\n", 16); |
| |
| idx = 0; |
| blkNum = 0; |
| |
| /* Fill remaining blocks with B */ |
| while (len-- > 0) { |
| block_x[idx] ^= *bytes++; |
| if (++idx >= 16) { |
| idx = 0; |
| show_block(block_x, "After xor: ", "\n", blkNum); |
| dwc_wusb_aes_encrypt(block_x, key, block_x); |
| show_block(block_x, "After AES: ", "\n", blkNum); |
| blkNum++; |
| } |
| } |
| |
| /* Handle partial last block */ |
| if (idx > 0) { |
| show_block(block_x, "After xor: ", "\n", blkNum); |
| dwc_wusb_aes_encrypt(block_x, key, block_x); |
| show_block(block_x, "After AES: ", "\n", blkNum); |
| } |
| |
| /* Save the MIC tag */ |
| DWC_MEMCPY(block_t, block_x, 8); |
| show_block(block_t, "MIC tag : ", NULL, 8); |
| |
| /* Fill block A0 from flags = 0x01, N, and counter = 0 */ |
| block_m[0] = 0x01; |
| block_m[14] = 0; |
| block_m[15] = 0; |
| |
| /* Encrypt the counter */ |
| dwc_wusb_aes_encrypt(block_m, key, block_x); |
| show_block(block_x, "CTR[MIC] : ", NULL, 8); |
| |
| /* XOR with MIC tag */ |
| for (idx = 0; idx < 8; idx++) { |
| block_t[idx] ^= block_x[idx]; |
| } |
| |
| /* Return result to caller */ |
| DWC_MEMCPY(result, block_t, 8); |
| show_block(result, "CCM-MIC : ", NULL, 8); |
| |
| } |
| |
| /** |
| * The PRF function described in section 6.5 of the WUSB spec. This function |
| * concatenates MIC values returned from dwc_cmf() to create a value of |
| * the requested length. |
| * |
| * @param prf_len Length of the PRF function in bits (64, 128, or 256). |
| * @param key, nonce, label, bytes, len Same as for dwc_cmf(). |
| * @param result Byte array to receive the result. |
| */ |
| void dwc_wusb_prf(int prf_len, u8 *key, |
| u8 *nonce, char *label, u8 *bytes, int len, u8 *result) |
| { |
| int i; |
| |
| nonce[0] = 0; |
| for (i = 0; i < prf_len >> 6; i++, nonce[0]++) { |
| dwc_wusb_cmf(key, nonce, label, bytes, len, result); |
| result += 8; |
| } |
| } |
| |
| /** |
| * Fills in CCM Nonce per the WUSB spec. |
| * |
| * @param[in] haddr Host address. |
| * @param[in] daddr Device address. |
| * @param[in] tkid Session Key(PTK) identifier. |
| * @param[out] nonce Pointer to where the CCM Nonce output is to be written. |
| */ |
| void dwc_wusb_fill_ccm_nonce(uint16_t haddr, uint16_t daddr, uint8_t *tkid, |
| uint8_t *nonce) |
| { |
| |
| DWC_DEBUG("%s %x %x\n", __func__, daddr, haddr); |
| |
| DWC_MEMSET(&nonce[0], 0, 16); |
| |
| DWC_MEMCPY(&nonce[6], tkid, 3); |
| nonce[9] = daddr & 0xFF; |
| nonce[10] = (daddr >> 8) & 0xFF; |
| nonce[11] = haddr & 0xFF; |
| nonce[12] = (haddr >> 8) & 0xFF; |
| |
| dump_bytes("CCM nonce", nonce, 16); |
| } |
| |
| /** |
| * Generates a 16-byte cryptographic-grade random number for the Host/Device |
| * Nonce. |
| */ |
| void dwc_wusb_gen_nonce(uint16_t addr, uint8_t *nonce) |
| { |
| uint8_t inonce[16]; |
| uint32_t temp[4]; |
| |
| /* Fill in the Nonce */ |
| DWC_MEMSET(&inonce[0], 0, sizeof(inonce)); |
| inonce[9] = addr & 0xFF; |
| inonce[10] = (addr >> 8) & 0xFF; |
| inonce[11] = inonce[9]; |
| inonce[12] = inonce[10]; |
| |
| /* Collect "randomness samples" */ |
| DWC_RANDOM_BYTES((uint8_t *)temp, 16); |
| |
| dwc_wusb_prf_128((uint8_t *)temp, nonce, |
| "Random Numbers", (uint8_t *)temp, sizeof(temp), |
| nonce); |
| } |
| |
| /** |
| * Generates the Session Key (PTK) and Key Confirmation Key (KCK) per the |
| * WUSB spec. |
| * |
| * @param[in] ccm_nonce Pointer to CCM Nonce. |
| * @param[in] mk Master Key to derive the session from |
| * @param[in] hnonce Pointer to Host Nonce. |
| * @param[in] dnonce Pointer to Device Nonce. |
| * @param[out] kck Pointer to where the KCK output is to be written. |
| * @param[out] ptk Pointer to where the PTK output is to be written. |
| */ |
| void dwc_wusb_gen_key(uint8_t *ccm_nonce, uint8_t *mk, uint8_t *hnonce, |
| uint8_t *dnonce, uint8_t *kck, uint8_t *ptk) |
| { |
| uint8_t idata[32]; |
| uint8_t odata[32]; |
| |
| dump_bytes("ck", mk, 16); |
| dump_bytes("hnonce", hnonce, 16); |
| dump_bytes("dnonce", dnonce, 16); |
| |
| /* The data is the HNonce and DNonce concatenated */ |
| DWC_MEMCPY(&idata[0], hnonce, 16); |
| DWC_MEMCPY(&idata[16], dnonce, 16); |
| |
| dwc_wusb_prf_256(mk, ccm_nonce, "Pair-wise keys", idata, 32, odata); |
| |
| /* Low 16 bytes of the result is the KCK, high 16 is the PTK */ |
| DWC_MEMCPY(kck, &odata[0], 16); |
| DWC_MEMCPY(ptk, &odata[16], 16); |
| |
| dump_bytes("kck", kck, 16); |
| dump_bytes("ptk", ptk, 16); |
| } |
| |
| /** |
| * Generates the Message Integrity Code over the Handshake data per the |
| * WUSB spec. |
| * |
| * @param ccm_nonce Pointer to CCM Nonce. |
| * @param kck Pointer to Key Confirmation Key. |
| * @param data Pointer to Handshake data to be checked. |
| * @param mic Pointer to where the MIC output is to be written. |
| */ |
| void dwc_wusb_gen_mic(uint8_t *ccm_nonce, uint8_t *kck, |
| uint8_t *data, uint8_t *mic) |
| { |
| |
| dwc_wusb_prf_64(kck, ccm_nonce, "out-of-bandMIC", |
| data, WUSB_HANDSHAKE_LEN_FOR_MIC, mic); |
| } |
| |
| #endif /* DWC_CRYPTOLIB */ |