/** * @brief CBC Encrypt data stream with null padding at the end. * * This function preforms CBC Encryption in the actual mode with actual key * and portions of AES_BLOCKSIZE length. * If the last block has less than AES_BLOCKSIZE bytes, it is padded with * null bytes to this length and then encrypted. * * No result is return; the CBC-MAC must be read separately. * * @param start Pointer to start address * @param buflen Number of bytes to be encrypted; if 0, nothing happens */ void encrypt_with_padding(uint8_t *start, uint8_t buflen) { /* Encrypt the "full blocks". */ while (buflen >= AES_BLOCKSIZE) { #if (SAL_TYPE == AT86RF2xx) sal_aes_wrrd(start, NULL); #else sal_aes_exec(start); #endif start += AES_BLOCKSIZE; buflen -= AES_BLOCKSIZE; } /* Pad the possible rest and encrypt it. */ if (buflen) { uint8_t locbuf[AES_BLOCKSIZE]; memcpy(locbuf, start, buflen); memset(locbuf + buflen, 0, AES_BLOCKSIZE - buflen); #if (SAL_TYPE == AT86RF2xx) sal_aes_wrrd(locbuf, NULL); #else sal_aes_exec(locbuf); #endif } }
void encrypt_pldmic(uint8_t *buffer, uint8_t *nonce, uint8_t mic_len, uint8_t pld_len) { uint8_t ctr; uint8_t i; uint8_t keystream[AES_BLOCKSIZE]; uint8_t *keystreamptr; int spld_len; spld_len = (int)pld_len; /* max. value: 0x7f */ sal_aes_setup(NULL, AES_MODE_ECB, AES_DIR_ENCRYPT); ctr = 0; while (spld_len > 0) { /* Compute the keystream block. */ nonce[AES_BLOCKSIZE - 1] = ++ctr; sal_aes_exec(nonce); sal_aes_read(keystream); /* En/decrypt payload. */ for (i = MIN(spld_len, AES_BLOCKSIZE), keystreamptr = keystream; i--; /* */) { *buffer++ ^= *keystreamptr++; } spld_len -= AES_BLOCKSIZE; } /* En/decrypt MIC. */ if (mic_len) { /* Prepare the keystream for MIC. */ nonce[AES_BLOCKSIZE - 1] = 0; sal_aes_exec(nonce); sal_aes_read(keystream); for (i = mic_len, keystreamptr = keystream; i--; /* */) { *buffer++ ^= *keystreamptr++; } } }
/** * @brief Computes MIC * * This function computes the MIC according to CCM. * * The key was initialized in other functions before. * * @param[in] buffer Input data (frame, not padded yet) * @param[out] mic Computed MIC of size AES_BLOCKSIZE * @param[in] nonce The nonce: Initialization Vector (IV) as used in * cryptography; the ZigBee nonce are the bytes 2...14 * of this nonce * @param[in] hdr_len Size of plain text header in bytes (may be 0) * @param[in] pld_len Length of payload in bytes (may be 0) */ void compute_mic(uint8_t *buffer, uint8_t *mic, uint8_t *nonce, uint8_t hdr_len, uint8_t pld_len) { sal_aes_setup(NULL, AES_MODE_ECB, AES_DIR_ENCRYPT); #if (SAL_TYPE == AT86RF2xx) sal_aes_wrrd(nonce, NULL); #else sal_aes_exec(nonce); #endif sal_aes_setup(NULL, AES_MODE_CBC, AES_DIR_ENCRYPT); if (hdr_len) { uint8_t locbuf[AES_BLOCKSIZE]; uint8_t firstlen; firstlen = MIN(AES_BLOCKSIZE - 2, hdr_len); /* Prepend L(a). */ locbuf[0] = 0; locbuf[1] = hdr_len; memcpy(locbuf + 2, buffer, firstlen); encrypt_with_padding(locbuf, firstlen + 2); if (firstlen < hdr_len) { /* No padding up to now since firstlen is AES_BLOCKSIZE *- 2. */ encrypt_with_padding(buffer + firstlen, hdr_len - firstlen); } } encrypt_with_padding(buffer + hdr_len, pld_len); sal_aes_read(mic); }
/*************************************************************************//** *****************************************************************************/ void PHY_EncryptReq(uint8_t *text, uint8_t *key) { sal_aes_setup(key, AES_MODE_ECB, AES_DIR_ENCRYPT); sal_aes_exec(text); sal_aes_read(text); }
/** * @brief Setup AES unit * * This function performs the following tasks as part of the setup of the * AES unit: key initialization, set encryption direction and encryption mode. * * In general, the contents of SRAM buffer is destroyed. When using * sal_aes_wrrd(), sal_aes_read() needs to be called in order to get the result * of the last AES operation before you may call sal_aes_setup() again. * * @param[in] key AES key or NULL (NULL: use last key) * @param[in] enc_mode AES_MODE_ECB or AES_MODE_CBC * @param[in] dir AES_DIR_ENCRYPT or AES_DIR_DECRYPT * * @return False if some parameter was illegal, true else */ bool sal_aes_setup(uint8_t *key, uint8_t enc_mode, uint8_t dir) { uint8_t i; /* Init mode_byte: AES low-level interrupt and autostart enabled */ mode_byte = COMP_SR(AES_INTLVL0, 1) | COMP_SR(AES_AUTO, 1); if (key != NULL) { /* Setup for new key. */ dec_initialized = false; last_dir = AES_DIR_VOID; /* Save key for later use after decryption or sleep. */ memcpy(enc_key, key, AES_KEYSIZE); keyp = enc_key; } /* Set encryption direction. */ switch (dir) { case AES_DIR_ENCRYPT: if (last_dir == AES_DIR_DECRYPT) { /* * If the last operation was decryption, the encryption * key must be stored in enc_key, so re-initialize it. */ keyp = enc_key; } break; case AES_DIR_DECRYPT: if (last_dir != AES_DIR_DECRYPT) { if (!dec_initialized) { uint8_t dummy[AES_BLOCKSIZE]; /* Compute decryption key. */ /* Dummy ECB encryption. */ AES_CTRL = mode_byte; keyp = enc_key; sal_aes_exec(dummy); /* Read last round key. */ for (i = 0; i < AES_BLOCKSIZE; ++i) { dec_key[i] = AES_KEY; } dec_initialized = true; } keyp = dec_key; } break; default: return false; } last_dir = dir; /* Set encryption mode and direction. */ switch (enc_mode) { case AES_MODE_ECB: case AES_MODE_CBC: { uint8_t xorflag; uint8_t dirflag = 0; xorflag = (enc_mode == AES_MODE_CBC); dirflag = (dir == AES_DIR_DECRYPT); mode_byte |= COMP_SR(AES_XOR, xorflag) | COMP_SR(AES_DECRYPT, dirflag); AES_CTRL = mode_byte; } break; default: return (false); } return (true); }