blob: 3b0353296148f6297b5bdc2f45e9fe92a17c680d [file] [log] [blame]
/* =========================================================================
* $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 */