| | | 1 | | using System; |
| | | 2 | | using System.Collections.Generic; |
| | | 3 | | |
| | | 4 | | namespace Renci.SshNet.Security.Chaos.NaCl.Internal |
| | | 5 | | { |
| | | 6 | | internal class Poly1305Donna |
| | | 7 | | { |
| | | 8 | | // written by floodyberry (Andrew M.) |
| | | 9 | | // original license: MIT or PUBLIC DOMAIN |
| | | 10 | | // https://github.com/floodyberry/poly1305-donna/blob/master/poly1305-donna-unrolled.c |
| | | 11 | | internal static void poly1305_auth(byte[] output, int outputOffset, byte[] m, int mStart, int mLength, ref Array |
| | 0 | 12 | | { |
| | | 13 | | UInt32 t0, t1, t2, t3; |
| | | 14 | | UInt32 h0, h1, h2, h3, h4; |
| | | 15 | | UInt32 r0, r1, r2, r3, r4; |
| | | 16 | | UInt32 s1, s2, s3, s4; |
| | | 17 | | UInt32 b, nb; |
| | | 18 | | int j; |
| | | 19 | | UInt64 tt0, tt1, tt2, tt3, tt4; |
| | | 20 | | UInt64 f0, f1, f2, f3; |
| | | 21 | | UInt32 g0, g1, g2, g3, g4; |
| | | 22 | | UInt64 c; |
| | | 23 | | |
| | | 24 | | /* clamp key */ |
| | 0 | 25 | | t0 = key.x0; |
| | 0 | 26 | | t1 = key.x1; |
| | 0 | 27 | | t2 = key.x2; |
| | 0 | 28 | | t3 = key.x3; |
| | | 29 | | |
| | | 30 | | /* precompute multipliers */ |
| | 0 | 31 | | r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; |
| | 0 | 32 | | r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; |
| | 0 | 33 | | r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; |
| | 0 | 34 | | r3 = t2 & 0x3f03fff; t3 >>= 8; |
| | 0 | 35 | | r4 = t3 & 0x00fffff; |
| | | 36 | | |
| | 0 | 37 | | s1 = r1 * 5; |
| | 0 | 38 | | s2 = r2 * 5; |
| | 0 | 39 | | s3 = r3 * 5; |
| | 0 | 40 | | s4 = r4 * 5; |
| | | 41 | | |
| | | 42 | | /* init state */ |
| | 0 | 43 | | h0 = 0; |
| | 0 | 44 | | h1 = 0; |
| | 0 | 45 | | h2 = 0; |
| | 0 | 46 | | h3 = 0; |
| | 0 | 47 | | h4 = 0; |
| | | 48 | | |
| | | 49 | | /* full blocks */ |
| | 0 | 50 | | if (mLength < 16) |
| | 0 | 51 | | goto poly1305_donna_atmost15bytes; |
| | | 52 | | |
| | 0 | 53 | | poly1305_donna_16bytes: |
| | 0 | 54 | | mStart += 16; |
| | 0 | 55 | | mLength -= 16; |
| | | 56 | | |
| | 0 | 57 | | t0 = ByteIntegerConverter.LoadLittleEndian32(m, mStart - 16); |
| | 0 | 58 | | t1 = ByteIntegerConverter.LoadLittleEndian32(m, mStart - 12); |
| | 0 | 59 | | t2 = ByteIntegerConverter.LoadLittleEndian32(m, mStart - 8); |
| | 0 | 60 | | t3 = ByteIntegerConverter.LoadLittleEndian32(m, mStart - 4); |
| | | 61 | | |
| | | 62 | | //todo: looks like these can be simplified a bit |
| | 0 | 63 | | h0 += t0 & 0x3ffffff; |
| | 0 | 64 | | h1 += (uint)(((((UInt64)t1 << 32) | t0) >> 26) & 0x3ffffff); |
| | 0 | 65 | | h2 += (uint)(((((UInt64)t2 << 32) | t1) >> 20) & 0x3ffffff); |
| | 0 | 66 | | h3 += (uint)(((((UInt64)t3 << 32) | t2) >> 14) & 0x3ffffff); |
| | 0 | 67 | | h4 += (t3 >> 8) | (1 << 24); |
| | | 68 | | |
| | | 69 | | |
| | 0 | 70 | | poly1305_donna_mul: |
| | 0 | 71 | | tt0 = (ulong)h0 * r0 + (ulong)h1 * s4 + (ulong)h2 * s3 + (ulong)h3 * s2 + (ulong)h4 * s1; |
| | 0 | 72 | | tt1 = (ulong)h0 * r1 + (ulong)h1 * r0 + (ulong)h2 * s4 + (ulong)h3 * s3 + (ulong)h4 * s2; |
| | 0 | 73 | | tt2 = (ulong)h0 * r2 + (ulong)h1 * r1 + (ulong)h2 * r0 + (ulong)h3 * s4 + (ulong)h4 * s3; |
| | 0 | 74 | | tt3 = (ulong)h0 * r3 + (ulong)h1 * r2 + (ulong)h2 * r1 + (ulong)h3 * r0 + (ulong)h4 * s4; |
| | 0 | 75 | | tt4 = (ulong)h0 * r4 + (ulong)h1 * r3 + (ulong)h2 * r2 + (ulong)h3 * r1 + (ulong)h4 * r0; |
| | | 76 | | |
| | | 77 | | unchecked |
| | 0 | 78 | | { |
| | 0 | 79 | | h0 = (UInt32)tt0 & 0x3ffffff; c = (tt0 >> 26); |
| | 0 | 80 | | tt1 += c; h1 = (UInt32)tt1 & 0x3ffffff; b = (UInt32)(tt1 >> 26); |
| | 0 | 81 | | tt2 += b; h2 = (UInt32)tt2 & 0x3ffffff; b = (UInt32)(tt2 >> 26); |
| | 0 | 82 | | tt3 += b; h3 = (UInt32)tt3 & 0x3ffffff; b = (UInt32)(tt3 >> 26); |
| | 0 | 83 | | tt4 += b; h4 = (UInt32)tt4 & 0x3ffffff; b = (UInt32)(tt4 >> 26); |
| | 0 | 84 | | } |
| | 0 | 85 | | h0 += b * 5; |
| | | 86 | | |
| | 0 | 87 | | if (mLength >= 16) |
| | 0 | 88 | | goto poly1305_donna_16bytes; |
| | | 89 | | |
| | | 90 | | /* final bytes */ |
| | 0 | 91 | | poly1305_donna_atmost15bytes: |
| | 0 | 92 | | if (mLength == 0) |
| | 0 | 93 | | goto poly1305_donna_finish; |
| | | 94 | | |
| | 0 | 95 | | byte[] mp = new byte[16];//todo remove allocation |
| | | 96 | | |
| | 0 | 97 | | for (j = 0; j < mLength; j++) |
| | 0 | 98 | | mp[j] = m[mStart + j]; |
| | 0 | 99 | | mp[j++] = 1; |
| | 0 | 100 | | for (; j < 16; j++) |
| | 0 | 101 | | mp[j] = 0; |
| | 0 | 102 | | mLength = 0; |
| | | 103 | | |
| | 0 | 104 | | t0 = ByteIntegerConverter.LoadLittleEndian32(mp, 0); |
| | 0 | 105 | | t1 = ByteIntegerConverter.LoadLittleEndian32(mp, 4); |
| | 0 | 106 | | t2 = ByteIntegerConverter.LoadLittleEndian32(mp, 8); |
| | 0 | 107 | | t3 = ByteIntegerConverter.LoadLittleEndian32(mp, 12); |
| | 0 | 108 | | CryptoBytes.Wipe(mp); |
| | | 109 | | |
| | 0 | 110 | | h0 += t0 & 0x3ffffff; |
| | 0 | 111 | | h1 += (uint)(((((UInt64)t1 << 32) | t0) >> 26) & 0x3ffffff); |
| | 0 | 112 | | h2 += (uint)(((((UInt64)t2 << 32) | t1) >> 20) & 0x3ffffff); |
| | 0 | 113 | | h3 += (uint)(((((UInt64)t3 << 32) | t2) >> 14) & 0x3ffffff); |
| | 0 | 114 | | h4 += t3 >> 8; |
| | | 115 | | |
| | 0 | 116 | | goto poly1305_donna_mul; |
| | | 117 | | |
| | 0 | 118 | | poly1305_donna_finish: |
| | 0 | 119 | | b = h0 >> 26; h0 = h0 & 0x3ffffff; |
| | 0 | 120 | | h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; |
| | 0 | 121 | | h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; |
| | 0 | 122 | | h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; |
| | 0 | 123 | | h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; |
| | 0 | 124 | | h0 += b * 5; |
| | | 125 | | |
| | 0 | 126 | | g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; |
| | 0 | 127 | | g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; |
| | 0 | 128 | | g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; |
| | 0 | 129 | | g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; |
| | 0 | 130 | | g4 = unchecked(h4 + b - (1 << 26)); |
| | | 131 | | |
| | 0 | 132 | | b = (g4 >> 31) - 1; |
| | 0 | 133 | | nb = ~b; |
| | 0 | 134 | | h0 = (h0 & nb) | (g0 & b); |
| | 0 | 135 | | h1 = (h1 & nb) | (g1 & b); |
| | 0 | 136 | | h2 = (h2 & nb) | (g2 & b); |
| | 0 | 137 | | h3 = (h3 & nb) | (g3 & b); |
| | 0 | 138 | | h4 = (h4 & nb) | (g4 & b); |
| | | 139 | | |
| | 0 | 140 | | f0 = ((h0) | (h1 << 26)) + (UInt64)key.x4; |
| | 0 | 141 | | f1 = ((h1 >> 6) | (h2 << 20)) + (UInt64)key.x5; |
| | 0 | 142 | | f2 = ((h2 >> 12) | (h3 << 14)) + (UInt64)key.x6; |
| | 0 | 143 | | f3 = ((h3 >> 18) | (h4 << 8)) + (UInt64)key.x7; |
| | | 144 | | |
| | | 145 | | unchecked |
| | 0 | 146 | | { |
| | 0 | 147 | | ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 0, (uint)f0); f1 += (f0 >> 32); |
| | 0 | 148 | | ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 4, (uint)f1); f2 += (f1 >> 32); |
| | 0 | 149 | | ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 8, (uint)f2); f3 += (f2 >> 32); |
| | 0 | 150 | | ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 12, (uint)f3); |
| | 0 | 151 | | } |
| | 0 | 152 | | } |
| | | 153 | | } |
| | | 154 | | } |