amcl/
gcm.rs

1/*
2Licensed to the Apache Software Foundation (ASF) under one
3or more contributor license agreements.  See the NOTICE file
4distributed with this work for additional information
5regarding copyright ownership.  The ASF licenses this file
6to you under the Apache License, Version 2.0 (the
7"License"); you may not use this file except in compliance
8with the License.  You may obtain a copy of the License at
9
10  http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing,
13software distributed under the License is distributed on an
14"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15KIND, either express or implied.  See the License for the
16specific language governing permissions and limitations
17under the License.
18*/
19
20const GCM_NB: usize = 4;
21const GCM_ACCEPTING_HEADER: usize = 0;
22const GCM_ACCEPTING_CIPHER: usize = 1;
23const GCM_NOT_ACCEPTING_MORE: usize = 2;
24const GCM_FINISHED: usize = 3;
25const GCM_ENCRYPTING: usize = 0;
26const GCM_DECRYPTING: usize = 1;
27
28use crate::aes;
29use crate::aes::AES;
30
31pub struct GCM {
32    table: [[u32; 4]; 128],
33    statex: [u8; 16],
34    y_0: [u8; 16],
35    //  counter: usize,
36    lena: [u32; 2],
37    lenc: [u32; 2],
38    status: usize,
39    a: AES,
40}
41
42impl GCM {
43    fn pack(b: [u8; 4]) -> u32 {
44        /* pack bytes into a 32-bit Word */
45        return ((((b[0]) & 0xff) as u32) << 24)
46            | ((((b[1]) & 0xff) as u32) << 16)
47            | ((((b[2]) & 0xff) as u32) << 8)
48            | (((b[3]) & 0xff) as u32);
49    }
50
51    fn unpack(a: u32) -> [u8; 4] {
52        /* unpack bytes from a word */
53        let b: [u8; 4] = [
54            ((a >> 24) & 0xff) as u8,
55            ((a >> 16) & 0xff) as u8,
56            ((a >> 8) & 0xff) as u8,
57            (a & 0xff) as u8,
58        ];
59        return b;
60    }
61
62    fn precompute(&mut self, h: &[u8]) {
63        let mut b: [u8; 4] = [0; 4];
64        let mut j = 0;
65        for i in 0..GCM_NB {
66            b[0] = h[j];
67            b[1] = h[j + 1];
68            b[2] = h[j + 2];
69            b[3] = h[j + 3];
70            self.table[0][i] = GCM::pack(b);
71            j += 4;
72        }
73        for i in 1..128 {
74            let mut c: u32 = 0;
75            for j in 0..GCM_NB {
76                self.table[i][j] = c | (self.table[i - 1][j]) >> 1;
77                c = self.table[i - 1][j] << 31;
78            }
79            if c != 0 {
80                self.table[i][0] ^= 0xE1000000
81            } /* irreducible polynomial */
82        }
83    }
84
85    fn gf2mul(&mut self) {
86        /* gf2m mul - Z=H*X mod 2^128 */
87        let mut p: [u32; 4] = [0; 4];
88
89        for i in 0..4 {
90            p[i] = 0
91        }
92        let mut j: usize = 8;
93        let mut m = 0;
94        for i in 0..128 {
95            j -= 1;
96            let mut c = ((self.statex[m] >> j) & 1) as u32;
97            c = (!c) + 1;
98            for k in 0..GCM_NB {
99                p[k] ^= self.table[i][k] & c
100            }
101            if j == 0 {
102                j = 8;
103                m += 1;
104                if m == 16 {
105                    break;
106                }
107            }
108        }
109        j = 0;
110        for i in 0..GCM_NB {
111            let b = GCM::unpack(p[i]);
112            self.statex[j] = b[0];
113            self.statex[j + 1] = b[1];
114            self.statex[j + 2] = b[2];
115            self.statex[j + 3] = b[3];
116            j += 4;
117        }
118    }
119
120    fn wrap(&mut self) {
121        /* Finish off GHASH */
122        let mut f: [u32; 4] = [0; 4];
123        let mut el: [u8; 16] = [0; 16];
124
125        /* convert lengths from bytes to bits */
126        f[0] = (self.lena[0] << 3) | (self.lena[1] & 0xE0000000) >> 29;
127        f[1] = self.lena[1] << 3;
128        f[2] = (self.lenc[0] << 3) | (self.lenc[1] & 0xE0000000) >> 29;
129        f[3] = self.lenc[1] << 3;
130        let mut j = 0;
131        for i in 0..GCM_NB {
132            let b = GCM::unpack(f[i]);
133            el[j] = b[0];
134            el[j + 1] = b[1];
135            el[j + 2] = b[2];
136            el[j + 3] = b[3];
137            j += 4;
138        }
139        for i in 0..16 {
140            self.statex[i] ^= el[i]
141        }
142        self.gf2mul();
143    }
144
145    fn ghash(&mut self, plain: &[u8], len: usize) -> bool {
146        if self.status == GCM_ACCEPTING_HEADER {
147            self.status = GCM_ACCEPTING_CIPHER
148        }
149        if self.status != GCM_ACCEPTING_CIPHER {
150            return false;
151        }
152
153        let mut j = 0;
154        while j < len {
155            for i in 0..16 {
156                if j >= len {
157                    break;
158                }
159                self.statex[i] ^= plain[j];
160                j += 1;
161                self.lenc[1] += 1;
162                if self.lenc[1] == 0 {
163                    self.lenc[0] += 1
164                }
165            }
166            self.gf2mul();
167        }
168        if len % 16 != 0 {
169            self.status = GCM_NOT_ACCEPTING_MORE
170        }
171        return true;
172    }
173
174    /* Initialize GCM mode */
175    pub fn init(&mut self, nk: usize, key: &[u8], niv: usize, iv: &[u8]) {
176        /* iv size niv is usually 12 bytes (96 bits). AES key size nk can be 16,24 or 32 bytes */
177        let mut h: [u8; 16] = [0; 16];
178
179        for i in 0..16 {
180            h[i] = 0;
181            self.statex[i] = 0
182        }
183
184        self.a = AES::new();
185
186        self.a.init(aes::ECB, nk, key, None);
187        self.a.ecb_encrypt(&mut h); /* E(K,0) */
188        self.precompute(&h);
189
190        self.lena[0] = 0;
191        self.lenc[0] = 0;
192        self.lena[1] = 0;
193        self.lenc[1] = 0;
194        if niv == 12 {
195            for i in 0..12 {
196                self.a.f[i] = iv[i]
197            }
198            let b = GCM::unpack(1);
199            self.a.f[12] = b[0];
200            self.a.f[13] = b[1];
201            self.a.f[14] = b[2];
202            self.a.f[15] = b[3]; /* initialise IV */
203            for i in 0..16 {
204                self.y_0[i] = self.a.f[i]
205            }
206        } else {
207            self.status = GCM_ACCEPTING_CIPHER;
208            self.ghash(iv, niv); /* GHASH(H,0,IV) */
209            self.wrap();
210            for i in 0..16 {
211                self.a.f[i] = self.statex[i];
212                self.y_0[i] = self.a.f[i];
213                self.statex[i] = 0
214            }
215            self.lena[0] = 0;
216            self.lenc[0] = 0;
217            self.lena[1] = 0;
218            self.lenc[1] = 0;
219        }
220        self.status = GCM_ACCEPTING_HEADER;
221    }
222
223    pub fn new() -> GCM {
224        GCM {
225            table: [[0; 4]; 128],
226            statex: [0; 16],
227            y_0: [0; 16],
228            //counter:0,
229            lena: [0; 2],
230            lenc: [0; 2],
231            status: 0,
232            a: AES::new(),
233        }
234    }
235
236    /* Add Header data - included but not encrypted */
237    pub fn add_header(&mut self, header: &[u8], len: usize) -> bool {
238        /* Add some header. Won't be encrypted, but will be authenticated. len is length of header */
239        if self.status != GCM_ACCEPTING_HEADER {
240            return false;
241        }
242        let mut j = 0;
243        while j < len {
244            for i in 0..16 {
245                if j >= len {
246                    break;
247                }
248                self.statex[i] ^= header[j];
249                j += 1;
250                self.lena[1] += 1;
251                if self.lena[1] == 0 {
252                    self.lena[0] += 1
253                }
254            }
255            self.gf2mul();
256        }
257        if len % 16 != 0 {
258            self.status = GCM_ACCEPTING_CIPHER
259        }
260        return true;
261    }
262
263    /* Add Plaintext - included and encrypted */
264    pub fn add_plain(&mut self, cipher: &mut [u8], plain: &[u8], len: usize) -> bool {
265        let mut cb: [u8; 16] = [0; 16];
266        let mut b: [u8; 4] = [0; 4];
267
268        let mut counter: u32;
269        if self.status == GCM_ACCEPTING_HEADER {
270            self.status = GCM_ACCEPTING_CIPHER
271        }
272        if self.status != GCM_ACCEPTING_CIPHER {
273            return false;
274        }
275
276        let mut j = 0;
277        while j < len {
278            b[0] = self.a.f[12];
279            b[1] = self.a.f[13];
280            b[2] = self.a.f[14];
281            b[3] = self.a.f[15];
282            counter = GCM::pack(b);
283            counter += 1;
284            b = GCM::unpack(counter);
285            self.a.f[12] = b[0];
286            self.a.f[13] = b[1];
287            self.a.f[14] = b[2];
288            self.a.f[15] = b[3]; /* increment counter */
289            for i in 0..16 {
290                cb[i] = self.a.f[i]
291            }
292            self.a.ecb_encrypt(&mut cb); /* encrypt it  */
293
294            for i in 0..16 {
295                if j >= len {
296                    break;
297                }
298                cipher[j] = plain[j] ^ cb[i];
299                self.statex[i] ^= cipher[j];
300                j += 1;
301                self.lenc[1] += 1;
302                if self.lenc[1] == 0 {
303                    self.lenc[0] += 1
304                }
305            }
306            self.gf2mul()
307        }
308        if len % 16 != 0 {
309            self.status = GCM_NOT_ACCEPTING_MORE
310        }
311        return true;
312    }
313
314    /* Add Ciphertext - decrypts to plaintext */
315    pub fn add_cipher(&mut self, plain: &mut [u8], cipher: &[u8], len: usize) -> bool {
316        let mut cb: [u8; 16] = [0; 16];
317        let mut b: [u8; 4] = [0; 4];
318
319        let mut counter: u32;
320
321        if self.status == GCM_ACCEPTING_HEADER {
322            self.status = GCM_ACCEPTING_CIPHER
323        }
324        if self.status != GCM_ACCEPTING_CIPHER {
325            return false;
326        }
327
328        let mut j = 0;
329        while j < len {
330            b[0] = self.a.f[12];
331            b[1] = self.a.f[13];
332            b[2] = self.a.f[14];
333            b[3] = self.a.f[15];
334            counter = GCM::pack(b);
335            counter += 1;
336            b = GCM::unpack(counter);
337            self.a.f[12] = b[0];
338            self.a.f[13] = b[1];
339            self.a.f[14] = b[2];
340            self.a.f[15] = b[3]; /* increment counter */
341            for i in 0..16 {
342                cb[i] = self.a.f[i]
343            }
344            self.a.ecb_encrypt(&mut cb); /* encrypt it  */
345            for i in 0..16 {
346                if j >= len {
347                    break;
348                }
349                let oc = cipher[j];
350                plain[j] = cipher[j] ^ cb[i];
351                self.statex[i] ^= oc;
352                j += 1;
353                self.lenc[1] += 1;
354                if self.lenc[1] == 0 {
355                    self.lenc[0] += 1
356                }
357            }
358            self.gf2mul()
359        }
360        if len % 16 != 0 {
361            self.status = GCM_NOT_ACCEPTING_MORE
362        }
363        return true;
364    }
365
366    /* Finish and extract Tag */
367    pub fn finish(&mut self, extract: bool) -> [u8; 16] {
368        /* Finish off GHASH and extract tag (MAC) */
369        let mut tag: [u8; 16] = [0; 16];
370
371        self.wrap();
372        /* extract tag */
373        if extract {
374            self.a.ecb_encrypt(&mut (self.y_0)); /* E(K,Y0) */
375            for i in 0..16 {
376                self.y_0[i] ^= self.statex[i]
377            }
378            for i in 0..16 {
379                tag[i] = self.y_0[i];
380                self.y_0[i] = 0;
381                self.statex[i] = 0
382            }
383        }
384        self.status = GCM_FINISHED;
385        self.a.end();
386        return tag;
387    }
388
389    pub fn hex2bytes(hex: &[u8], bin: &mut [u8]) {
390        let len = hex.len();
391
392        for i in 0..len / 2 {
393            let mut v: u8;
394            let mut c = hex[2 * i];
395            if c >= b'0' && c <= b'9' {
396                v = c - b'0';
397            } else if c >= b'A' && c <= b'F' {
398                v = c - b'A' + 10;
399            } else if c >= b'a' && c <= b'f' {
400                v = c - b'a' + 10;
401            } else {
402                v = 0;
403            }
404            v <<= 4;
405            c = hex[2 * i + 1];
406            if c >= b'0' && c <= b'9' {
407                v += c - b'0';
408            } else if c >= b'A' && c <= b'F' {
409                v += c - b'A' + 10;
410            } else if c >= b'a' && c <= b'f' {
411                v += c - b'a' + 10;
412            } else {
413                v = 0;
414            }
415            bin[i] = v;
416        }
417    }
418}
419/*
420fn main()
421{
422    let kt=b"feffe9928665731c6d6a8f9467308308";
423    let mt=b"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39";
424    let ht=b"feedfacedeadbeeffeedfacedeadbeefabaddad2";
425    let nt=b"9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b";
426// Tag should be 619cc5aefffe0bfa462af43c1699d050
427
428    let mut gcm=GCM::new();
429
430    let len=mt.len()/2;
431    let lenh=ht.len()/2;
432    let lenk=kt.len()/2;
433    let leniv=nt.len()/2;
434
435    //let mut t:[u8;16]=[0;16]; // Tag
436    let mut k:[u8;16]=[0;16];   // AES Key
437    let mut h:[u8;64]=[0;64];   // Header - to be included in Authentication, but not encrypted
438    let mut n:[u8;100]=[0;100]; // IV - Initialisation vector
439    let mut m:[u8;100]=[0;100]; // Plaintext to be encrypted/authenticated
440    let mut c:[u8;100]=[0;100]; // Ciphertext
441    let mut p:[u8;100]=[0;100]; // Recovered Plaintext
442
443    GCM::hex2bytes(mt,&mut m);
444    GCM::hex2bytes(ht,&mut h);
445    GCM::hex2bytes(kt,&mut k);
446    GCM::hex2bytes(nt,&mut n);
447
448     println!("Plaintext=");
449    for i in 0..len {print!("{:02x}",m[i])}
450    println!("");
451
452    gcm.init(lenk,&k,leniv,&n);
453
454    gcm.add_header(&h,lenh);
455    gcm.add_plain(&mut c,&m,len);
456    let mut t=gcm.finish(true);
457
458     println!("Ciphertext=");
459    for i in 0..len {print!("{:02x}",c[i])}
460    println!("");
461
462     println!("Tag=");
463    for i in 0..16 {print!("{:02x}",t[i])}
464    println!("");
465
466    gcm.init(lenk,&k,leniv,&n);
467
468    gcm.add_header(&h,lenh);
469    gcm.add_cipher(&mut p,&c,len);
470    t=gcm.finish(true);
471
472     println!("Plaintext=");
473    for i in 0..len {print!("{:02x}",p[i])}
474    println!("");
475
476    println!("Tag=");
477    for i in 0..16 {print!("{:02x}",t[i])}
478    println!("");
479
480}
481*/