summaryrefslogtreecommitdiffstats
path: root/utils/imxtools/sbtools/crypto.cpp
blob: 5563fcfd3b806619af7267e21f73f6b855b2c4b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2016 Amaury Pouly
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/
#include "crypto.h"
#include "misc.h"
#include <cryptopp/modes.h>
#include <cryptopp/aes.h>
#include <cryptopp/sha.h>

using namespace CryptoPP;

namespace
{

enum crypto_method_t g_cur_method = CRYPTO_NONE;
uint8_t g_key[16];
CBC_Mode<AES>::Encryption g_aes_enc;
CBC_Mode<AES>::Decryption g_aes_dec;
bool g_aes_enc_key_dirty; /* true of g_aes_enc key needs to be updated */
bool g_aes_dec_key_dirty; /* same for g_aes_dec */

int cbc_mac2(
    const uint8_t *in_data, /* Input data */
    uint8_t *out_data, /* Output data (or NULL) */
    int nr_blocks, /* Number of blocks to encrypt/decrypt (one block=16 bytes) */
    uint8_t key[16], /* Key */
    uint8_t iv[16], /* Initialisation Vector */
    uint8_t (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
    bool encrypt /* 1 to encrypt, 0 to decrypt */
    )
{
    /* encrypt */
    if(encrypt)
    {
        /* update keys if neeeded */
        if(g_aes_enc_key_dirty)
        {
            /* we need to provide an IV with the key, although we change it
             * everytime we run the cipher anyway */
            g_aes_enc.SetKeyWithIV(g_key, 16, iv, 16);
            g_aes_enc_key_dirty = false;
        }
        g_aes_enc.Resynchronize(iv, 16);
        uint8_t tmp[16];
        /* we need some output buffer, either a temporary one if we are CBC-MACing
         * only, or use output buffer if available */
        uint8_t *out_ptr = (out_data == NULL) ? tmp : out_data;
        while(nr_blocks-- > 0)
        {
            g_aes_enc.ProcessData(out_ptr, in_data, 16);
            /* if this is the last block, copy CBC-MAC */
            if(nr_blocks == 0 && out_cbc_mac)
                memcpy(out_cbc_mac, out_ptr, 16);
            /* if we are writing data to the output buffer, advance output pointer */
            if(out_data != NULL)
                out_ptr += 16;
            in_data += 16;
        }
        return CRYPTO_ERROR_SUCCESS;
    }
    /* decrypt */
    else
    {
        /* update keys if neeeded */
        if(g_aes_dec_key_dirty)
        {
            /* we need to provide an IV with the key, although we change it
             * everytime we run the cipher anyway */
            g_aes_dec.SetKeyWithIV(g_key, 16, iv, 16);
            g_aes_dec_key_dirty = false;
        }
        /* we cannot produce a CBC-MAC in decrypt mode, output buffer exists */
        if(out_cbc_mac || out_data == NULL)
            return CRYPTO_ERROR_INVALID_OP;
        g_aes_dec.Resynchronize(iv, 16);
        g_aes_dec.ProcessData(out_data, in_data, nr_blocks * 16);
        return CRYPTO_ERROR_SUCCESS;
    }
}

}

int crypto_setup(struct crypto_key_t *key)
{
    g_cur_method = key->method;
    switch(g_cur_method)
    {
        case CRYPTO_KEY:
            memcpy(g_key, key->u.key, 16);
            g_aes_dec_key_dirty = true;
            g_aes_enc_key_dirty = true;
            return CRYPTO_ERROR_SUCCESS;
        default:
            return CRYPTO_ERROR_BADSETUP;
    }
}

int crypto_apply(
    uint8_t *in_data, /* Input data */
    uint8_t *out_data, /* Output data (or NULL) */
    int nr_blocks, /* Number of blocks (one block=16 bytes) */
    uint8_t iv[16], /* Key */
    uint8_t (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
    bool encrypt)
{
    if(g_cur_method == CRYPTO_KEY)
        return cbc_mac2(in_data, out_data, nr_blocks, g_key, iv, out_cbc_mac, encrypt);
    else
        return CRYPTO_ERROR_BADSETUP;
}

void sha_1_init(struct sha_1_params_t *params)
{
    params->object = new SHA1;
}

void sha_1_update(struct sha_1_params_t *params, uint8_t *buffer, int size)
{
    reinterpret_cast<SHA1 *>(params->object)->Update(buffer, size);
}

void sha_1_finish(struct sha_1_params_t *params)
{
    SHA1 *obj = reinterpret_cast<SHA1 *>(params->object);
    obj->Final(params->hash);
    delete obj;
}

void sha_1_output(struct sha_1_params_t *params, uint8_t *out)
{
    memcpy(out, params->hash, 20);
}