1 package org.bouncycastle.crypto.digests; 2 3 import org.bouncycastle.crypto.BlockCipher; 4 import org.bouncycastle.crypto.ExtendedDigest; 5 import org.bouncycastle.crypto.engines.GOST28147Engine; 6 import org.bouncycastle.crypto.params.KeyParameter; 7 import org.bouncycastle.crypto.params.ParametersWithSBox; 8 import org.bouncycastle.util.Arrays; 9 import org.bouncycastle.util.Memoable; 10 import org.bouncycastle.util.Pack; 11 12 /** 13 * implementation of GOST R 34.11-94 14 */ 15 public class GOST3411Digest 16 implements ExtendedDigest, Memoable 17 { 18 private static final int DIGEST_LENGTH = 32; 19 20 private byte[] H = new byte[32], L = new byte[32], 21 M = new byte[32], Sum = new byte[32]; 22 private byte[][] C = new byte[4][32]; 23 24 private byte[] xBuf = new byte[32]; 25 private int xBufOff; 26 private long byteCount; 27 28 private BlockCipher cipher = new GOST28147Engine(); 29 private byte[] sBox; 30 31 /** 32 * Standard constructor 33 */ GOST3411Digest()34 public GOST3411Digest() 35 { 36 sBox = GOST28147Engine.getSBox("D-A"); 37 cipher.init(true, new ParametersWithSBox(null, sBox)); 38 39 reset(); 40 } 41 42 /** 43 * Constructor to allow use of a particular sbox with GOST28147 44 * @see GOST28147Engine#getSBox(String) 45 */ GOST3411Digest(byte[] sBoxParam)46 public GOST3411Digest(byte[] sBoxParam) 47 { 48 sBox = Arrays.clone(sBoxParam); 49 cipher.init(true, new ParametersWithSBox(null, sBox)); 50 51 reset(); 52 } 53 54 /** 55 * Copy constructor. This will copy the state of the provided 56 * message digest. 57 */ GOST3411Digest(GOST3411Digest t)58 public GOST3411Digest(GOST3411Digest t) 59 { 60 reset(t); 61 } 62 getAlgorithmName()63 public String getAlgorithmName() 64 { 65 return "GOST3411"; 66 } 67 getDigestSize()68 public int getDigestSize() 69 { 70 return DIGEST_LENGTH; 71 } 72 update(byte in)73 public void update(byte in) 74 { 75 xBuf[xBufOff++] = in; 76 if (xBufOff == xBuf.length) 77 { 78 sumByteArray(xBuf); // calc sum M 79 processBlock(xBuf, 0); 80 xBufOff = 0; 81 } 82 byteCount++; 83 } 84 update(byte[] in, int inOff, int len)85 public void update(byte[] in, int inOff, int len) 86 { 87 while ((xBufOff != 0) && (len > 0)) 88 { 89 update(in[inOff]); 90 inOff++; 91 len--; 92 } 93 94 while (len > xBuf.length) 95 { 96 System.arraycopy(in, inOff, xBuf, 0, xBuf.length); 97 98 sumByteArray(xBuf); // calc sum M 99 processBlock(xBuf, 0); 100 inOff += xBuf.length; 101 len -= xBuf.length; 102 byteCount += xBuf.length; 103 } 104 105 // load in the remainder. 106 while (len > 0) 107 { 108 update(in[inOff]); 109 inOff++; 110 len--; 111 } 112 } 113 114 // (i + 1 + 4(k - 1)) = 8i + k i = 0-3, k = 1-8 115 private byte[] K = new byte[32]; 116 P(byte[] in)117 private byte[] P(byte[] in) 118 { 119 for(int k = 0; k < 8; k++) 120 { 121 K[4*k] = in[k]; 122 K[1 + 4*k] = in[ 8 + k]; 123 K[2 + 4*k] = in[16 + k]; 124 K[3 + 4*k] = in[24 + k]; 125 } 126 127 return K; 128 } 129 130 //A (x) = (x0 ^ x1) || x3 || x2 || x1 131 byte[] a = new byte[8]; A(byte[] in)132 private byte[] A(byte[] in) 133 { 134 for(int j=0; j<8; j++) 135 { 136 a[j]=(byte)(in[j] ^ in[j+8]); 137 } 138 139 System.arraycopy(in, 8, in, 0, 24); 140 System.arraycopy(a, 0, in, 24, 8); 141 142 return in; 143 } 144 145 //Encrypt function, ECB mode E(byte[] key, byte[] s, int sOff, byte[] in, int inOff)146 private void E(byte[] key, byte[] s, int sOff, byte[] in, int inOff) 147 { 148 cipher.init(true, new KeyParameter(key)); 149 150 cipher.processBlock(in, inOff, s, sOff); 151 } 152 153 // (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2 154 short[] wS = new short[16], w_S = new short[16]; 155 fw(byte[] in)156 private void fw(byte[] in) 157 { 158 cpyBytesToShort(in, wS); 159 w_S[15] = (short)(wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]); 160 System.arraycopy(wS, 1, w_S, 0, 15); 161 cpyShortToBytes(w_S, in); 162 } 163 164 // block processing 165 byte[] S = new byte[32]; 166 byte[] U = new byte[32], V = new byte[32], W = new byte[32]; 167 processBlock(byte[] in, int inOff)168 protected void processBlock(byte[] in, int inOff) 169 { 170 System.arraycopy(in, inOff, M, 0, 32); 171 172 //key step 1 173 174 // H = h3 || h2 || h1 || h0 175 // S = s3 || s2 || s1 || s0 176 System.arraycopy(H, 0, U, 0, 32); 177 System.arraycopy(M, 0, V, 0, 32); 178 for (int j=0; j<32; j++) 179 { 180 W[j] = (byte)(U[j]^V[j]); 181 } 182 // Encrypt gost28147-ECB 183 E(P(W), S, 0, H, 0); // s0 = EK0 [h0] 184 185 //keys step 2,3,4 186 for (int i=1; i<4; i++) 187 { 188 byte[] tmpA = A(U); 189 for (int j=0; j<32; j++) 190 { 191 U[j] = (byte)(tmpA[j] ^ C[i][j]); 192 } 193 V = A(A(V)); 194 for (int j=0; j<32; j++) 195 { 196 W[j] = (byte)(U[j]^V[j]); 197 } 198 // Encrypt gost28147-ECB 199 E(P(W), S, i * 8, H, i * 8); // si = EKi [hi] 200 } 201 202 // x(M, H) = y61(H^y(M^y12(S))) 203 for(int n = 0; n < 12; n++) 204 { 205 fw(S); 206 } 207 for(int n = 0; n < 32; n++) 208 { 209 S[n] = (byte)(S[n] ^ M[n]); 210 } 211 212 fw(S); 213 214 for(int n = 0; n < 32; n++) 215 { 216 S[n] = (byte)(H[n] ^ S[n]); 217 } 218 for(int n = 0; n < 61; n++) 219 { 220 fw(S); 221 } 222 System.arraycopy(S, 0, H, 0, H.length); 223 } 224 finish()225 private void finish() 226 { 227 Pack.longToLittleEndian(byteCount * 8, L, 0); // get length into L (byteCount * 8 = bitCount) 228 229 while (xBufOff != 0) 230 { 231 update((byte)0); 232 } 233 234 processBlock(L, 0); 235 processBlock(Sum, 0); 236 } 237 doFinal( byte[] out, int outOff)238 public int doFinal( 239 byte[] out, 240 int outOff) 241 { 242 finish(); 243 244 System.arraycopy(H, 0, out, outOff, H.length); 245 246 reset(); 247 248 return DIGEST_LENGTH; 249 } 250 251 /** 252 * reset the chaining variables to the IV values. 253 */ 254 private static final byte[] C2 = { 255 0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF, 256 (byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00, 257 0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF,0x00,0x00,(byte)0xFF, 258 (byte)0xFF,0x00,0x00,0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF}; 259 reset()260 public void reset() 261 { 262 byteCount = 0; 263 xBufOff = 0; 264 265 for(int i=0; i<H.length; i++) 266 { 267 H[i] = 0; // start vector H 268 } 269 for(int i=0; i<L.length; i++) 270 { 271 L[i] = 0; 272 } 273 for(int i=0; i<M.length; i++) 274 { 275 M[i] = 0; 276 } 277 for(int i=0; i<C[1].length; i++) 278 { 279 C[1][i] = 0; // real index C = +1 because index array with 0. 280 } 281 for(int i=0; i<C[3].length; i++) 282 { 283 C[3][i] = 0; 284 } 285 for(int i=0; i<Sum.length; i++) 286 { 287 Sum[i] = 0; 288 } 289 for(int i = 0; i < xBuf.length; i++) 290 { 291 xBuf[i] = 0; 292 } 293 294 System.arraycopy(C2, 0, C[2], 0, C2.length); 295 } 296 297 // 256 bitsblock modul -> (Sum + a mod (2^256)) sumByteArray(byte[] in)298 private void sumByteArray(byte[] in) 299 { 300 int carry = 0; 301 302 for (int i = 0; i != Sum.length; i++) 303 { 304 int sum = (Sum[i] & 0xff) + (in[i] & 0xff) + carry; 305 306 Sum[i] = (byte)sum; 307 308 carry = sum >>> 8; 309 } 310 } 311 cpyBytesToShort(byte[] S, short[] wS)312 private void cpyBytesToShort(byte[] S, short[] wS) 313 { 314 for(int i=0; i<S.length/2; i++) 315 { 316 wS[i] = (short)(((S[i*2+1]<<8)&0xFF00)|(S[i*2]&0xFF)); 317 } 318 } 319 cpyShortToBytes(short[] wS, byte[] S)320 private void cpyShortToBytes(short[] wS, byte[] S) 321 { 322 for(int i=0; i<S.length/2; i++) 323 { 324 S[i*2 + 1] = (byte)(wS[i] >> 8); 325 S[i*2] = (byte)wS[i]; 326 } 327 } 328 getByteLength()329 public int getByteLength() 330 { 331 return 32; 332 } 333 copy()334 public Memoable copy() 335 { 336 return new GOST3411Digest(this); 337 } 338 reset(Memoable other)339 public void reset(Memoable other) 340 { 341 GOST3411Digest t = (GOST3411Digest)other; 342 343 this.sBox = t.sBox; 344 cipher.init(true, new ParametersWithSBox(null, sBox)); 345 346 reset(); 347 348 System.arraycopy(t.H, 0, this.H, 0, t.H.length); 349 System.arraycopy(t.L, 0, this.L, 0, t.L.length); 350 System.arraycopy(t.M, 0, this.M, 0, t.M.length); 351 System.arraycopy(t.Sum, 0, this.Sum, 0, t.Sum.length); 352 System.arraycopy(t.C[1], 0, this.C[1], 0, t.C[1].length); 353 System.arraycopy(t.C[2], 0, this.C[2], 0, t.C[2].length); 354 System.arraycopy(t.C[3], 0, this.C[3], 0, t.C[3].length); 355 System.arraycopy(t.xBuf, 0, this.xBuf, 0, t.xBuf.length); 356 357 this.xBufOff = t.xBufOff; 358 this.byteCount = t.byteCount; 359 } 360 } 361 362 363