-
Notifications
You must be signed in to change notification settings - Fork 8
/
chaskey.cpp
165 lines (154 loc) · 4.21 KB
/
chaskey.cpp
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/**
* Drop-in replacement for reference implementation of Chaskey MAC algorithm
* invented by Nicky Mouha http://mouha.be/chaskey/
*/
#include <assert.h>
#include "chaskey.hpp"
#ifndef CHASKEY_HEAD2HEAD_TEST
#include "chaskey.h"
#endif
namespace crypto {
namespace chaskey {
/** single chunk formatter to optimize access to a single chunk of data */
template<bool = details::arch_traits::direct_safe>
class single_chunk;
/* little-endian version with direct access to the data */
template<>
class single_chunk<true> : public details::simple_formatter<uint32_t,4> {
public:
typedef details::simple_formatter<uint32_t,4> base;
using typename base::block_t;
using typename base::size_t;
inline void attach(const uint8_t* msg, size_t len) noexcept {
size_t blocks = len ? (len - 1) / sizeof(block_t) : 0;
raw = reinterpret_cast<const block_t*>(msg);
end = raw + blocks;
size_t tail = (len % sizeof(block_t));
if( tail || ! len ) {
msg += len - tail;
base::append(msg, tail); /* side effect on tail and msg */
base::pad(1);
las = &base::block();
padded = true;
} else {
las = raw + blocks;
padded = false;
}
}
inline const block_t& block() const noexcept {
return *raw;
}
inline void reset() noexcept {
base::reset();
raw = &base::block();
}
inline void next() noexcept {
raw++;
}
inline const block_t& last() noexcept {
return *las;
}
/* returns true if has more that one block to process */
inline bool has() const noexcept {
return raw < end;
}
inline bool pad() const noexcept {
return padded;
}
private:
const block_t* raw;
const block_t* end;
const block_t* las;
bool padded;
};
/* big-endian full-buffered version */
template<>
class single_chunk<false> : public details::simple_formatter<uint32_t,4> {
public:
typedef details::simple_formatter<uint32_t,4> base;
using typename base::block_t;
using typename base::size_t;
inline void attach(const uint8_t* amsg, size_t alen) noexcept {
msg=amsg;
len = alen;
base::append(msg, len);
}
inline void next() noexcept {
reset();
base::append(msg, len);
}
inline const block_t& last() noexcept {
return base::block();
}
inline bool has() const noexcept {
return len;
}
inline bool pad() noexcept {
if( full() ) return false;
base::pad(1);
return true;
}
private:
const uint8_t* msg;
size_t len;
bool padded;
};
/**
* Chaskey8Alt - implements Chaskey message authentication algorithm
* optimized to work with single chunk of data
*/
class Chaskey8Alt : public Chaskey8 {
public:
typedef uint8_t tag_t[sizeof(block_t)];
/**
* computes message digest, and writes results to tag
*/
void sign(tag_t& tag, const uint8_t* msg, uint_fast16_t len,
const block_t& key, const block_t& subkey1,
const block_t& subkey2) noexcept {
single_chunk<> buff;
init(key);
buff.attach(msg, len);
const block_t* finalkey = &subkey1;
while( buff.has() ) {
*this ^= buff.block();
permute();
buff.next();
};
if( buff.pad() )
finalkey = &subkey2;
*this ^= buff.last();
*this ^= *finalkey;
permute();
*this ^= *finalkey;
buff.final(*this);
Block::cast(&tag) = v;
}
};
}}
using namespace crypto::chaskey;
inline const Chaskey8::block_t& cast(const uint32_t *key) noexcept {
return * reinterpret_cast<const Chaskey8::block_t*>(key);
}
inline Chaskey8::block_t & cast(uint32_t *key) noexcept {
return * reinterpret_cast<Chaskey8::block_t*>(key);
}
__attribute__((weak))
void subkeys(uint32_t k1[4], uint32_t k2[4], const uint32_t k[4]) {
const Chaskey8::block_t & key(cast(k));
Chaskey8::Block & key1(Chaskey8::cast(k1));
Chaskey8::Block & key2(Chaskey8::cast(k2));
Chaskey8::derive(key1, key);
Chaskey8::derive(key2, key1);
}
__attribute__((weak))
void chaskey(uint8_t *tag, uint32_t taglen, const uint8_t *m, const uint32_t mlen,
const uint32_t k[4], const uint32_t k1[4], const uint32_t k2[4]) {
assert(taglen<=sizeof(Chaskey8::tag_t));
Chaskey8Alt cipher;
cipher.sign(*reinterpret_cast<Chaskey8::tag_t*>(tag), m, mlen,
cast(k), cast(k1), cast(k2));
}
void (*chaskey_cpp)(uint8_t *, uint32_t, const uint8_t *, const uint32_t,
const uint32_t [4], const uint32_t [4], const uint32_t [4]) = &chaskey;
void (*subkeys_cpp)(uint32_t [4], uint32_t [4], const uint32_t [4]) = &subkeys;