Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers cipher_mode_ccm.c Source File

cipher_mode_ccm.c

Go to the documentation of this file.
00001 /**
00002  * @file cipher_mode_ccm.c
00003  * @brief Cipher Block Chaining-Message Authentication Code (CCM)
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneCrypto Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @section Description
00026  *
00027  * CCM mode (Cipher Block Chaining-Message Authentication Code) is a mode of
00028  * operation for cryptographic block ciphers. It is an authenticated encryption
00029  * algorithm designed to provide both authentication and confidentiality. CCM
00030  * mode is only defined for block ciphers with a block length of 128 bits.
00031  * Refer to SP 800-38D for more details
00032  *
00033  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00034  * @version 1.7.6
00035  **/
00036 
00037 //Switch to the appropriate trace level
00038 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
00039 
00040 //Dependencies
00041 #include <string.h>
00042 #include "crypto.h"
00043 #include "cipher_mode_ccm.h"
00044 #include "debug.h"
00045 
00046 //Check crypto library configuration
00047 #if (CCM_SUPPORT == ENABLED)
00048 
00049 
00050 /**
00051  * @brief Authenticated encryption using CCM
00052  * @param[in] cipher Cipher algorithm
00053  * @param[in] context Cipher algorithm context
00054  * @param[in] n Nonce
00055  * @param[in] nLen Length of the nonce
00056  * @param[in] a Additional authenticated data
00057  * @param[in] aLen Length of the additional data
00058  * @param[in] p Plaintext to be encrypted
00059  * @param[out] c Ciphertext resulting from the encryption
00060  * @param[in] length Total number of data bytes to be encrypted
00061  * @param[out] t MAC resulting from the encryption process
00062  * @param[in] tLen Length of the MAC
00063  * @return Error code
00064  **/
00065 
00066 error_t ccmEncrypt(const CipherAlgo *cipher, void *context, const uint8_t *n, size_t nLen,
00067    const uint8_t *a, size_t aLen, const uint8_t *p, uint8_t *c, size_t length, uint8_t *t, size_t tLen)
00068 {
00069    size_t m;
00070    size_t q;
00071    size_t qLen;
00072    uint8_t b[16];
00073    uint8_t y[16];
00074    uint8_t s[16];
00075 
00076    //Check parameters
00077    if(cipher == NULL || context == NULL)
00078       return ERROR_INVALID_PARAMETER;
00079 
00080    //CCM supports only symmetric block ciphers whose block size is 128 bits
00081    if(cipher->type != CIPHER_ALGO_TYPE_BLOCK || cipher->blockSize != 16)
00082       return ERROR_INVALID_PARAMETER;
00083 
00084    //Check the length of the nonce
00085    if(nLen < 7 || nLen > 13)
00086       return ERROR_INVALID_LENGTH;
00087    //Check the length of the MAC
00088    if(tLen < 4 || tLen > 16 || tLen % 2)
00089       return ERROR_INVALID_LENGTH;
00090 
00091    //Q is the bit string representation of the octet length of P
00092    q = length;
00093    //Compute the octet length of Q
00094    qLen = 15 - nLen;
00095 
00096    //Format the leading octet of the first block
00097    b[0] = (aLen > 0) ? 0x40 : 0x00;
00098    //Encode the octet length of T
00099    b[0] |= ((tLen - 2) / 2) << 3;
00100    //Encode the octet length of Q
00101    b[0] |= qLen - 1;
00102 
00103    //Copy the nonce
00104    memcpy(b + 1, n, nLen);
00105 
00106    //Encode the length field Q
00107    for(m = 0; m < qLen; m++, q >>= 8)
00108       b[15 - m] = q & 0xFF;
00109 
00110    //Invalid length?
00111    if(q != 0)
00112       return ERROR_INVALID_LENGTH;
00113 
00114    //Set Y(0) = CIPH(B(0))
00115    cipher->encryptBlock(context, b, y);
00116 
00117    //Any additional data?
00118    if(aLen > 0)
00119    {
00120       //Format the associated data
00121       memset(b, 0, 16);
00122 
00123       //Check the length of the associated data string
00124       if(aLen < 0xFF00)
00125       {
00126          //The length is encoded as 2 octets
00127          STORE16BE(aLen, b);
00128          //Number of bytes to copy
00129          m = MIN(aLen, 16 - 2);
00130          //Concatenate the associated data A
00131          memcpy(b + 2, a, m);
00132       }
00133       else
00134       {
00135          //The length is encoded as 6 octets
00136          b[0] = 0xFF;
00137          b[1] = 0xFE;
00138          //MSB is stored first
00139          STORE32BE(aLen, b + 2);
00140          //Number of bytes to copy
00141          m = MIN(aLen, 16 - 6);
00142          //Concatenate the associated data A
00143          memcpy(b + 6, a, m);
00144       }
00145 
00146       //XOR B(1) with Y(0)
00147       ccmXorBlock(y, b, y, 16);
00148       //Compute Y(1) = CIPH(B(1) ^ Y(0))
00149       cipher->encryptBlock(context, y, y);
00150 
00151       //Number of remaining data bytes
00152       aLen -= m;
00153       a += m;
00154 
00155       //Process the remaining data bytes
00156       while(aLen > 0)
00157       {
00158          //Associated data are processed in a block-by-block fashion
00159          m = MIN(aLen, 16);
00160 
00161          //XOR B(i) with Y(i-1)
00162          ccmXorBlock(y, a, y, m);
00163          //Compute Y(i) = CIPH(B(i) ^ Y(i-1))
00164          cipher->encryptBlock(context, y, y);
00165 
00166          //Next block
00167          aLen -= m;
00168          a += m;
00169       }
00170    }
00171 
00172    //Format CTR(0)
00173    b[0] = (uint8_t) (qLen - 1);
00174    //Copy the nonce
00175    memcpy(b + 1, n, nLen);
00176    //Initialize counter value
00177    memset(b + 1 + nLen, 0, qLen);
00178 
00179    //Compute S(0) = CIPH(CTR(0))
00180    cipher->encryptBlock(context, b, s);
00181    //Save MSB(S(0))
00182    memcpy(t, s, tLen);
00183 
00184    //Encrypt plaintext
00185    while(length > 0)
00186    {
00187       //The encryption operates in a block-by-block fashion
00188       m = MIN(length, 16);
00189 
00190       //XOR B(i) with Y(i-1)
00191       ccmXorBlock(y, p, y, m);
00192       //Compute Y(i) = CIPH(B(i) ^ Y(i-1))
00193       cipher->encryptBlock(context, y, y);
00194 
00195       //Increment counter
00196       ccmIncCounter(b, qLen);
00197       //Compute S(i) = CIPH(CTR(i))
00198       cipher->encryptBlock(context, b, s);
00199       //Compute C(i) = B(i) XOR S(i)
00200       ccmXorBlock(c, p, s, m);
00201 
00202       //Next block
00203       length -= m;
00204       p += m;
00205       c += m;
00206    }
00207 
00208    //Compute MAC
00209    ccmXorBlock(t, t, y, tLen);
00210 
00211    //Successful encryption
00212    return NO_ERROR;
00213 }
00214 
00215 
00216 /**
00217  * @brief Authenticated decryption using CCM
00218  * @param[in] cipher Cipher algorithm
00219  * @param[in] context Cipher algorithm context
00220  * @param[in] n Nonce
00221  * @param[in] nLen Length of the nonce
00222  * @param[in] a Additional authenticated data
00223  * @param[in] aLen Length of the additional data
00224  * @param[in] c Ciphertext to be decrypted
00225  * @param[out] p Plaintext resulting from the decryption
00226  * @param[in] length Total number of data bytes to be decrypted
00227  * @param[in] t MAC to be verified
00228  * @param[in] tLen Length of the MAC
00229  * @return Error code
00230  **/
00231 
00232 error_t ccmDecrypt(const CipherAlgo *cipher, void *context, const uint8_t *n, size_t nLen,
00233    const uint8_t *a, size_t aLen, const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
00234 {
00235    size_t m;
00236    size_t q;
00237    size_t qLen;
00238    uint8_t b[16];
00239    uint8_t y[16];
00240    uint8_t r[16];
00241    uint8_t s[16];
00242 
00243    //Check parameters
00244    if(cipher == NULL || context == NULL)
00245       return ERROR_INVALID_PARAMETER;
00246 
00247    //CCM supports only symmetric block ciphers whose block size is 128 bits
00248    if(cipher->type != CIPHER_ALGO_TYPE_BLOCK || cipher->blockSize != 16)
00249       return ERROR_INVALID_PARAMETER;
00250 
00251    //Check the length of the nonce
00252    if(nLen < 7 || nLen > 13)
00253       return ERROR_INVALID_LENGTH;
00254    //Check the length of the MAC
00255    if(tLen < 4 || tLen > 16 || tLen % 2)
00256       return ERROR_INVALID_LENGTH;
00257 
00258    //Q is the bit string representation of the octet length of C
00259    q = length;
00260    //Compute the octet length of Q
00261    qLen = 15 - nLen;
00262 
00263    //Format the leading octet of the first block
00264    b[0] = (aLen > 0) ? 0x40 : 0x00;
00265    //Encode the octet length of T
00266    b[0] |= ((tLen - 2) / 2) << 3;
00267    //Encode the octet length of Q
00268    b[0] |= qLen - 1;
00269 
00270    //Copy the nonce
00271    memcpy(b + 1, n, nLen);
00272 
00273    //Encode the length field Q
00274    for(m = 0; m < qLen; m++, q >>= 8)
00275       b[15 - m] = q & 0xFF;
00276 
00277    //Invalid length?
00278    if(q != 0)
00279       return ERROR_INVALID_LENGTH;
00280 
00281    //Set Y(0) = CIPH(B(0))
00282    cipher->encryptBlock(context, b, y);
00283 
00284    //Any additional data?
00285    if(aLen > 0)
00286    {
00287       //Format the associated data
00288       memset(b, 0, 16);
00289 
00290       //Check the length of the associated data string
00291       if(aLen < 0xFF00)
00292       {
00293          //The length is encoded as 2 octets
00294          STORE16BE(aLen, b);
00295          //Number of bytes to copy
00296          m = MIN(aLen, 16 - 2);
00297          //Concatenate the associated data A
00298          memcpy(b + 2, a, m);
00299       }
00300       else
00301       {
00302          //The length is encoded as 6 octets
00303          b[0] = 0xFF;
00304          b[1] = 0xFE;
00305          //MSB is stored first
00306          STORE32BE(aLen, b + 2);
00307          //Number of bytes to copy
00308          m = MIN(aLen, 16 - 6);
00309          //Concatenate the associated data A
00310          memcpy(b + 6, a, m);
00311       }
00312 
00313       //XOR B(1) with Y(0)
00314       ccmXorBlock(y, b, y, 16);
00315       //Compute Y(1) = CIPH(B(1) ^ Y(0))
00316       cipher->encryptBlock(context, y, y);
00317 
00318       //Number of remaining data bytes
00319       aLen -= m;
00320       a += m;
00321 
00322       //Process the remaining data bytes
00323       while(aLen > 0)
00324       {
00325          //Associated data are processed in a block-by-block fashion
00326          m = MIN(aLen, 16);
00327 
00328          //XOR B(i) with Y(i-1)
00329          ccmXorBlock(y, a, y, m);
00330          //Compute Y(i) = CIPH(B(i) ^ Y(i-1))
00331          cipher->encryptBlock(context, y, y);
00332 
00333          //Next block
00334          aLen -= m;
00335          a += m;
00336       }
00337    }
00338 
00339    //Format CTR(0)
00340    b[0] = (uint8_t) (qLen - 1);
00341    //Copy the nonce
00342    memcpy(b + 1, n, nLen);
00343    //Initialize counter value
00344    memset(b + 1 + nLen, 0, qLen);
00345 
00346    //Compute S(0) = CIPH(CTR(0))
00347    cipher->encryptBlock(context, b, s);
00348    //Save MSB(S(0))
00349    memcpy(r, s, tLen);
00350 
00351    //Decrypt ciphertext
00352    while(length > 0)
00353    {
00354       //The decryption operates in a block-by-block fashion
00355       m = MIN(length, 16);
00356 
00357       //Increment counter
00358       ccmIncCounter(b, qLen);
00359       //Compute S(i) = CIPH(CTR(i))
00360       cipher->encryptBlock(context, b, s);
00361       //Compute B(i) = C(i) XOR S(i)
00362       ccmXorBlock(p, c, s, m);
00363 
00364       //XOR B(i) with Y(i-1)
00365       ccmXorBlock(y, p, y, m);
00366       //Compute Y(i) = CIPH(B(i) ^ Y(i-1))
00367       cipher->encryptBlock(context, y, y);
00368 
00369       //Next block
00370       length -= m;
00371       c += m;
00372       p += m;
00373    }
00374 
00375    //Compute MAC
00376    ccmXorBlock(r, r, y, tLen);
00377 
00378    //The calculated tag is bitwise compared to the received tag. The
00379    //message is authenticated if and only if the tags match
00380    if(memcmp(r, t, tLen))
00381       return ERROR_FAILURE;
00382 
00383    //Successful decryption
00384    return NO_ERROR;
00385 }
00386 
00387 
00388 /**
00389  * @brief XOR operation
00390  * @param[out] x Block resulting from the XOR operation
00391  * @param[in] a First block
00392  * @param[in] b Second block
00393  * @param[in] n Size of the block
00394  **/
00395 
00396 void ccmXorBlock(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n)
00397 {
00398    size_t i;
00399 
00400    //Perform XOR operation
00401    for(i = 0; i < n; i++)
00402       x[i] = a[i] ^ b[i];
00403 }
00404 
00405 
00406 /**
00407  * @brief Increment counter block
00408  * @param[in,out] x Pointer to the counter block
00409  * @param[in] n Size in bytes of the specific part of the block to be incremented
00410  **/
00411 
00412 void ccmIncCounter(uint8_t *x, size_t n)
00413 {
00414    size_t i;
00415 
00416    //The function increments the right-most bytes of the block. The remaining
00417    //left-most bytes remain unchanged
00418    for(i = 0; i < n; i++)
00419    {
00420       //Increment the current byte and propagate the carry if necessary
00421       if(++(x[15 - i]) != 0)
00422          break;
00423    }
00424 }
00425 
00426 #endif
00427