4 * The One-key CBC MAC (OMAC) message authentication code,
\r
5 * designed by T. Iwata and K. Kurosawa.
\r
7 * @author Paulo S. L. M. Barreto
\r
11 * This software is hereby placed in the public domain.
\r
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
\r
14 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
\r
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
\r
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
\r
17 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
\r
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
\r
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
\r
20 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
\r
21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
\r
22 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
23 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
26 #include <freeradius-devel/ident.h>
\r
41 memset(L, (byte)0, sizeof(L));
\r
42 memset(T, (byte)0, sizeof(L));
\r
51 memset(L, (byte)0, sizeof(L));
\r
52 memset(T, (byte)0, sizeof(L));
\r
55 void OMAC::init(BlockCipher* E) {
\r
57 throw "Invalid block cipher";
\r
60 t = block_size = _E->blockSize();
\r
61 if (block_size != 16 && block_size != 8) {
\r
62 throw "Block size not supported";
\r
64 mask = (block_size == 16) ? 0x87 : 0x1B;
\r
65 // compute padding mask:
\r
66 memset(L, (byte)0, block_size);
\r
67 _E->encrypt(L, L); // L = E_K(0^n)
\r
68 uint c = L[0] & 0x80; // carry
\r
69 for (uint b = 0; b < block_size - 1; b++) {
\r
70 L[b] = (byte)((L[b] << 1) | ((L[b + 1] & 0xff) >> 7));
\r
72 L[block_size - 1] = (byte)((L[block_size - 1] << 1) ^ (c != 0 ? mask : 0)); // B = 2L
\r
73 // initialize tag accumulator
\r
74 memset(T, (byte)0, block_size);
\r
78 void OMAC::update(const byte* M, uint m) {
\r
80 throw "OMAC computation not initialized";
\r
82 uint i = block_size - t;
\r
84 while (m > t) { // N.B. m is strictly larger than t!
\r
85 // complete tag block:
\r
86 for (uint b = 0; b < t; b++) {
\r
87 T[i + b] ^= M[j + b];
\r
89 _E->encrypt(T, T); // since there is more data, no padding applies
\r
90 // proceed to the next block:
\r
97 // process remaining chunk (m bytes):
\r
98 for (uint b = 0; b < m; b++) {
\r
99 T[i + b] ^= M[j + b];
\r
102 //assert(m == 0 || t < block_size); // m == 0 here only occurs if m == 0 from the very beginning
\r
105 void OMAC::final(byte* tag) {
\r
107 // compute padding:
\r
109 // compute special padding mask:
\r
110 uint c = L[0] & 0x80; // carry
\r
111 for (uint b = 0; b < block_size - 1; b++) {
\r
112 L[b] = (byte)((L[b] << 1) | ((L[b + 1] & 0xff) >> 7));
\r
114 L[block_size - 1] = (byte)((L[block_size - 1] << 1) ^ (c != 0 ? mask : 0)); // P = 4L
\r
115 // pad incomplete block:
\r
116 T[block_size - t] ^= 0x80; // padding toggle
\r
119 for (uint b = 0; b < block_size; b++) {
\r
122 _E->encrypt(T, T); // T contains the complete tag
\r
123 ready = 1; // OMAC tag available
\r
124 _E = 0; // OMAC computation is complete; context no longer initialized
\r
125 } else if (!ready) {
\r
126 throw "OMAC computation not initialized";
\r
128 memcpy(tag, T, block_size);
\r