Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers chacha20_poly1305.c Source File

chacha20_poly1305.c

Go to the documentation of this file.
00001 /**
00002  * @file chacha20_poly1305.c
00003  * @brief ChaCha20Poly1305 AEAD
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  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <string.h>
00034 #include "crypto.h"
00035 #include "chacha.h"
00036 #include "poly1305.h"
00037 #include "chacha20_poly1305.h"
00038 #include "debug.h"
00039 
00040 //Check crypto library configuration
00041 #if (CHACHA20_POLY1305_SUPPORT == ENABLED)
00042 
00043 
00044 /**
00045  * @brief Authenticated encryption using ChaCha20Poly1305
00046  * @param[in] k key
00047  * @param[in] kLen Length of the key
00048  * @param[in] n Nonce
00049  * @param[in] nLen Length of the nonce
00050  * @param[in] a Additional authenticated data
00051  * @param[in] aLen Length of the additional data
00052  * @param[in] p Plaintext to be encrypted
00053  * @param[out] c Ciphertext resulting from the encryption
00054  * @param[in] length Total number of data bytes to be encrypted
00055  * @param[out] t MAC resulting from the encryption process
00056  * @param[in] tLen Length of the MAC
00057  * @return Error code
00058  **/
00059 
00060 error_t chacha20Poly1305Encrypt(const uint8_t *k, size_t kLen,
00061    const uint8_t *n, size_t nLen, const uint8_t *a, size_t aLen,
00062    const uint8_t *p, uint8_t *c, size_t length, uint8_t *t, size_t tLen)
00063 {
00064    error_t error;
00065    size_t paddingLen;
00066    ChachaContext chachaContext;
00067    Poly1305Context poly1305Context;
00068    uint8_t temp[32];
00069 
00070    //Check the length of the message-authentication code
00071    if(tLen != 16)
00072       return ERROR_INVALID_LENGTH;
00073 
00074    //Initialize ChaCha20 context
00075    error = chachaInit(&chachaContext, 20, k, kLen, n, nLen);
00076    //Any error to report?
00077    if(error)
00078       return error;
00079 
00080    //First, a Poly1305 one-time key is generated from the 256-bit key
00081    //and nonce
00082    chachaCipher(&chachaContext, NULL, temp, 32);
00083 
00084    //The other 256 bits of the Chacha20 block are discarded
00085    chachaCipher(&chachaContext, NULL, NULL, 32);
00086 
00087    //Next, the ChaCha20 encryption function is called to encrypt the
00088    //plaintext, using the same key and nonce
00089    chachaCipher(&chachaContext, p, c, length);
00090 
00091    //Initialize the Poly1305 function with the key calculated above
00092    poly1305Init(&poly1305Context, temp);
00093 
00094    //Compute MAC over the AAD
00095    poly1305Update(&poly1305Context, a, aLen);
00096 
00097    //If the length of the AAD is not an integral multiple of 16 bytes,
00098    //then padding is required
00099    if(aLen % 16)
00100    {
00101       //Compute the number of padding bytes
00102       paddingLen = 16 - (aLen % 16);
00103 
00104       //The padding is up to 15 zero bytes, and it brings the total
00105       //length so far to an integral multiple of 16
00106       memset(temp, 0, paddingLen);
00107 
00108       //Compute MAC over the padding
00109       poly1305Update(&poly1305Context, temp, paddingLen);
00110    }
00111 
00112    //Compute MAC over the ciphertext
00113    poly1305Update(&poly1305Context, c, length);
00114 
00115    //If the length of the ciphertext is not an integral multiple of 16 bytes,
00116    //then padding is required
00117    if(length % 16)
00118    {
00119       //Compute the number of padding bytes
00120       paddingLen = 16 - (length % 16);
00121 
00122       //The padding is up to 15 zero bytes, and it brings the total
00123       //length so far to an integral multiple of 16
00124       memset(temp, 0, paddingLen);
00125 
00126       //Compute MAC over the padding
00127       poly1305Update(&poly1305Context, temp, paddingLen);
00128    }
00129 
00130    //Encode the length of the AAD as a 64-bit little-endian integer
00131    STORE64LE(aLen, temp);
00132    //Compute MAC over the length field
00133    poly1305Update(&poly1305Context, temp, sizeof(uint64_t));
00134 
00135    //Encode the length of the ciphertext as a 64-bit little-endian integer
00136    STORE64LE(length, temp);
00137    //Compute MAC over the length field
00138    poly1305Update(&poly1305Context, temp, sizeof(uint64_t));
00139 
00140    //Compute message-authentication code
00141    poly1305Final(&poly1305Context, t);
00142 
00143    //Successful encryption
00144    return NO_ERROR;
00145 }
00146 
00147 
00148 /**
00149  * @brief Authenticated decryption using ChaCha20Poly1305
00150  * @param[in] k key
00151  * @param[in] kLen Length of the key
00152  * @param[in] n Nonce
00153  * @param[in] nLen Length of the nonce
00154  * @param[in] a Additional authenticated data
00155  * @param[in] aLen Length of the additional data
00156  * @param[in] c Ciphertext to be decrypted
00157  * @param[out] p Plaintext resulting from the decryption
00158  * @param[in] length Total number of data bytes to be decrypted
00159  * @param[in] t MAC to be verified
00160  * @param[in] tLen Length of the MAC
00161  * @return Error code
00162  **/
00163 
00164 error_t chacha20Poly1305Decrypt(const uint8_t *k, size_t kLen,
00165    const uint8_t *n, size_t nLen, const uint8_t *a, size_t aLen,
00166    const uint8_t *c, uint8_t *p, size_t length, const uint8_t *t, size_t tLen)
00167 {
00168    error_t error;
00169    size_t paddingLen;
00170    ChachaContext chachaContext;
00171    Poly1305Context poly1305Context;
00172    uint8_t temp[32];
00173 
00174    //Check the length of the message-authentication code
00175    if(tLen != 16)
00176       return ERROR_INVALID_LENGTH;
00177 
00178    //Initialize ChaCha20 context
00179    error = chachaInit(&chachaContext, 20, k, kLen, n, nLen);
00180    //Any error to report?
00181    if(error)
00182       return error;
00183 
00184    //First, a Poly1305 one-time key is generated from the 256-bit key
00185    //and nonce
00186    chachaCipher(&chachaContext, NULL, temp, 32);
00187 
00188    //The other 256 bits of the Chacha20 block are discarded
00189    chachaCipher(&chachaContext, NULL, NULL, 32);
00190 
00191    //Initialize the Poly1305 function with the key calculated above
00192    poly1305Init(&poly1305Context, temp);
00193 
00194    //Compute MAC over the AAD
00195    poly1305Update(&poly1305Context, a, aLen);
00196 
00197    //If the length of the AAD is not an integral multiple of 16 bytes,
00198    //then padding is required
00199    if(aLen % 16)
00200    {
00201       //Compute the number of padding bytes
00202       paddingLen = 16 - (aLen % 16);
00203 
00204       //The padding is up to 15 zero bytes, and it brings the total
00205       //length so far to an integral multiple of 16
00206       memset(temp, 0, paddingLen);
00207 
00208       //Compute MAC over the padding
00209       poly1305Update(&poly1305Context, temp, paddingLen);
00210    }
00211 
00212    //Compute MAC over the ciphertext
00213    poly1305Update(&poly1305Context, c, length);
00214 
00215    //If the length of the ciphertext is not an integral multiple of 16 bytes,
00216    //then padding is required
00217    if(length % 16)
00218    {
00219       //Compute the number of padding bytes
00220       paddingLen = 16 - (length % 16);
00221 
00222       //The padding is up to 15 zero bytes, and it brings the total
00223       //length so far to an integral multiple of 16
00224       memset(temp, 0, paddingLen);
00225 
00226       //Compute MAC over the padding
00227       poly1305Update(&poly1305Context, temp, paddingLen);
00228    }
00229 
00230    //Encode the length of the AAD as a 64-bit little-endian integer
00231    STORE64LE(aLen, temp);
00232    //Compute MAC over the length field
00233    poly1305Update(&poly1305Context, temp, sizeof(uint64_t));
00234 
00235    //Encode the length of the ciphertext as a 64-bit little-endian integer
00236    STORE64LE(length, temp);
00237    //Compute MAC over the length field
00238    poly1305Update(&poly1305Context, temp, sizeof(uint64_t));
00239 
00240    //Compute message-authentication code
00241    poly1305Final(&poly1305Context, temp);
00242 
00243    //Finally, we decrypt the ciphertext
00244    chachaCipher(&chachaContext, c, p, length);
00245 
00246    //The calculated tag is bitwise compared to the received tag. The
00247    //message is authenticated if and only if the tags match
00248    if(memcmp(temp, t, tLen))
00249       return ERROR_FAILURE;
00250 
00251    //Successful encryption
00252    return NO_ERROR;
00253 }
00254 
00255 #endif
00256