Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers rc6.c Source File

rc6.c

Go to the documentation of this file.
00001 /**
00002  * @file rc6.c
00003  * @brief RC6-32/20 block cipher
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  * RC6 is a symmetric key block cipher derived from RC5
00028  *
00029  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00030  * @version 1.7.6
00031  **/
00032 
00033 //Switch to the appropriate trace level
00034 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
00035 
00036 //Dependencies
00037 #include <string.h>
00038 #include "crypto.h"
00039 #include "rc6.h"
00040 
00041 //Check crypto library configuration
00042 #if (RC6_SUPPORT == ENABLED)
00043 
00044 //RC6 magic constants
00045 #define P32 0xB7E15163
00046 #define Q32 0x9E3779B9
00047 
00048 //Common interface for encryption algorithms
00049 const CipherAlgo rc6CipherAlgo =
00050 {
00051    "RC6",
00052    sizeof(Rc6Context),
00053    CIPHER_ALGO_TYPE_BLOCK,
00054    RC6_BLOCK_SIZE,
00055    (CipherAlgoInit) rc6Init,
00056    NULL,
00057    NULL,
00058    (CipherAlgoEncryptBlock) rc6EncryptBlock,
00059    (CipherAlgoDecryptBlock) rc6DecryptBlock
00060 };
00061 
00062 
00063 /**
00064  * @brief Initialize a RC6 context using the supplied key
00065  * @param[in] context Pointer to the RC6 context to initialize
00066  * @param[in] key Pointer to the key
00067  * @param[in] keyLength Length of the key
00068  * @return Error code
00069  **/
00070 
00071 error_t rc6Init(Rc6Context *context, const uint8_t *key, size_t keyLength)
00072 {
00073    uint_t c;
00074    uint_t i;
00075    uint_t j;
00076    uint_t s;
00077    uint_t v;
00078    uint32_t a;
00079    uint32_t b;
00080 
00081    //Invalid key length?
00082    if(keyLength > RC6_MAX_KEY_SIZE)
00083       return ERROR_INVALID_KEY_LENGTH;
00084 
00085    //Convert the secret key from bytes to words
00086    memset(context->l, 0, RC6_MAX_KEY_SIZE);
00087    memcpy(context->l, key, keyLength);
00088 
00089    //Calculate the length of the key in words
00090    c = (keyLength > 0) ? (keyLength + 3) / 4 : 1;
00091 
00092    //Initialize the first element of S
00093    context->s[0] = P32;
00094 
00095    //Initialize array S to a particular fixed pseudo random bit pattern
00096    for(i = 1; i < (2 * RC6_NB_ROUNDS + 4); i++)
00097       context->s[i] = context->s[i - 1] + Q32;
00098 
00099    //Initialize variables
00100    i = 0;
00101    j = 0;
00102    a = 0;
00103    b = 0;
00104 
00105    //Number of iterations
00106    v = 3 * MAX(c, 2 * RC6_NB_ROUNDS + 4);
00107 
00108    //Key expansion
00109    for(s = 0; s < v; s++)
00110    {
00111       context->s[i] += a + b;
00112       context->s[i] = ROL32(context->s[i], 3);
00113       a = context->s[i];
00114 
00115       context->l[j] += a + b;
00116       context->l[j] = ROL32(context->l[j], (a + b) % 32);
00117       b = context->l[j];
00118 
00119       if(++i >= (2 * RC6_NB_ROUNDS + 4))
00120          i = 0;
00121       if(++j >= c)
00122          j = 0;
00123    }
00124 
00125    //No error to report
00126    return NO_ERROR;
00127 }
00128 
00129 
00130 /**
00131  * @brief Encrypt a 16-byte block using RC6 algorithm
00132  * @param[in] context Pointer to the RC6 context
00133  * @param[in] input Plaintext block to encrypt
00134  * @param[out] output Ciphertext block resulting from encryption
00135  **/
00136 
00137 void rc6EncryptBlock(Rc6Context *context, const uint8_t *input, uint8_t *output)
00138 {
00139    uint_t i;
00140    uint32_t t;
00141    uint32_t u;
00142 
00143    //Load the 4 working registers with the plaintext
00144    uint32_t a = LOAD32LE(input + 0);
00145    uint32_t b = LOAD32LE(input + 4);
00146    uint32_t c = LOAD32LE(input + 8);
00147    uint32_t d = LOAD32LE(input + 12);
00148 
00149    //First, update B and D
00150    b += context->s[0];
00151    d += context->s[1];
00152 
00153    //Apply 20 rounds
00154    for(i = 1; i <= RC6_NB_ROUNDS; i++)
00155    {
00156       t = (b * (2 * b + 1));
00157       t = ROL32(t, 5);
00158 
00159       u = (d * (2 * d + 1));
00160       u = ROL32(u, 5);
00161 
00162       a ^= t;
00163       a = ROL32(a, u % 32) + context->s[2 * i];
00164 
00165       c ^= u;
00166       c = ROL32(c, t % 32) + context->s[2 * i + 1];
00167 
00168       t = a;
00169       a = b;
00170       b = c;
00171       c = d;
00172       d = t;
00173    }
00174 
00175    //Update A and C
00176    a += context->s[2 * RC6_NB_ROUNDS + 2];
00177    c += context->s[2 * RC6_NB_ROUNDS + 3];
00178 
00179    //The resulting value is the ciphertext
00180    STORE32LE(a, output + 0);
00181    STORE32LE(b, output + 4);
00182    STORE32LE(c, output + 8);
00183    STORE32LE(d, output + 12);
00184 }
00185 
00186 
00187 /**
00188  * @brief Decrypt a 16-byte block using RC6 algorithm
00189  * @param[in] context Pointer to the RC6 context
00190  * @param[in] input Ciphertext block to decrypt
00191  * @param[out] output Plaintext block resulting from decryption
00192  **/
00193 
00194 void rc6DecryptBlock(Rc6Context *context, const uint8_t *input, uint8_t *output)
00195 {
00196    uint_t i;
00197    uint32_t t;
00198    uint32_t u;
00199 
00200    //Load the 4 working registers with the ciphertext
00201    uint32_t a = LOAD32LE(input + 0);
00202    uint32_t b = LOAD32LE(input + 4);
00203    uint32_t c = LOAD32LE(input + 8);
00204    uint32_t d = LOAD32LE(input + 12);
00205 
00206    //First, update C and A
00207    c -= context->s[2 * RC6_NB_ROUNDS + 3];
00208    a -= context->s[2 * RC6_NB_ROUNDS + 2];
00209 
00210    //Apply 20 rounds
00211    for(i = RC6_NB_ROUNDS; i > 0; i--)
00212    {
00213       t = d;
00214       d = c;
00215       c = b;
00216       b = a;
00217       a = t;
00218 
00219       u = (d * (2 * d + 1));
00220       u = ROL32(u, 5);
00221 
00222       t = (b * (2 * b + 1));
00223       t = ROL32(t, 5);
00224 
00225       c -= context->s[2 * i + 1];
00226       c = ROR32(c, t % 32) ^ u;
00227 
00228       a -= context->s[2 * i];
00229       a = ROR32(a, u % 32) ^ t;
00230    }
00231 
00232    //Update D and B
00233    d -= context->s[1];
00234    b -= context->s[0];
00235 
00236    //The resulting value is the plaintext
00237    STORE32LE(a, output + 0);
00238    STORE32LE(b, output + 4);
00239    STORE32LE(c, output + 8);
00240    STORE32LE(d, output + 12);
00241 }
00242 
00243 #endif
00244