1 package org.bouncycastle.crypto.engines; 2 3 import org.bouncycastle.crypto.CipherParameters; 4 import org.bouncycastle.crypto.modes.GCFBBlockCipher; 5 import org.bouncycastle.crypto.params.KeyParameter; 6 import org.bouncycastle.crypto.params.ParametersWithIV; 7 import org.bouncycastle.crypto.params.ParametersWithRandom; 8 import org.bouncycastle.crypto.params.ParametersWithSBox; 9 import org.bouncycastle.crypto.params.ParametersWithUKM; 10 import org.bouncycastle.util.Pack; 11 12 public class CryptoProWrapEngine 13 extends GOST28147WrapEngine 14 { init(boolean forWrapping, CipherParameters param)15 public void init(boolean forWrapping, CipherParameters param) 16 { 17 if (param instanceof ParametersWithRandom) 18 { 19 ParametersWithRandom pr = (ParametersWithRandom)param; 20 param = pr.getParameters(); 21 } 22 23 ParametersWithUKM pU = (ParametersWithUKM)param; 24 byte[] sBox = null; 25 26 27 KeyParameter kParam; 28 29 if (pU.getParameters() instanceof ParametersWithSBox) 30 { 31 kParam = (KeyParameter)((ParametersWithSBox)pU.getParameters()).getParameters(); 32 sBox = ((ParametersWithSBox)pU.getParameters()).getSBox(); 33 } 34 else 35 { 36 kParam = (KeyParameter)pU.getParameters(); 37 } 38 39 kParam = new KeyParameter(cryptoProDiversify(kParam.getKey(), pU.getUKM(), sBox)); 40 41 if (sBox != null) 42 { 43 super.init(forWrapping, new ParametersWithUKM(new ParametersWithSBox(kParam, sBox), pU.getUKM())); 44 } 45 else 46 { 47 super.init(forWrapping, new ParametersWithUKM(kParam, pU.getUKM())); 48 } 49 } 50 51 /* 52 RFC 4357 6.5. CryptoPro KEK Diversification Algorithm 53 54 Given a random 64-bit UKM and a GOST 28147-89 key K, this algorithm 55 creates a new GOST 28147-89 key K(UKM). 56 57 1) Let K[0] = K; 58 2) UKM is split into components a[i,j]: 59 UKM = a[0]|..|a[7] (a[i] - byte, a[i,0]..a[i,7] - it's bits) 60 3) Let i be 0. 61 4) K[1]..K[8] are calculated by repeating the following algorithm 62 eight times: 63 A) K[i] is split into components k[i,j]: 64 K[i] = k[i,0]|k[i,1]|..|k[i,7] (k[i,j] - 32-bit integer) 65 B) Vector S[i] is calculated: 66 S[i] = ((a[i,0]*k[i,0] + ... + a[i,7]*k[i,7]) mod 2^32) | 67 (((~a[i,0])*k[i,0] + ... + (~a[i,7])*k[i,7]) mod 2^32); 68 C) K[i+1] = encryptCFB (S[i], K[i], K[i]) 69 D) i = i + 1 70 5) Let K(UKM) be K[8]. 71 */ cryptoProDiversify(byte[] K, byte[] ukm, byte[] sBox)72 private static byte[] cryptoProDiversify(byte[] K, byte[] ukm, byte[] sBox) 73 { 74 for (int i = 0; i != 8; i++) 75 { 76 int sOn = 0; 77 int sOff = 0; 78 for (int j = 0; j != 8; j++) 79 { 80 int kj = Pack.littleEndianToInt(K, j * 4); 81 if (bitSet(ukm[i], j)) 82 { 83 sOn += kj; 84 } 85 else 86 { 87 sOff += kj; 88 } 89 } 90 91 byte[] s = new byte[8]; 92 Pack.intToLittleEndian(sOn, s, 0); 93 Pack.intToLittleEndian(sOff, s, 4); 94 95 GCFBBlockCipher c = new GCFBBlockCipher(new GOST28147Engine()); 96 97 c.init(true, new ParametersWithIV(new ParametersWithSBox(new KeyParameter(K), sBox), s)); 98 99 c.processBlock(K, 0, K, 0); 100 c.processBlock(K, 8, K, 8); 101 c.processBlock(K, 16, K, 16); 102 c.processBlock(K, 24, K, 24); 103 } 104 105 return K; 106 } 107 bitSet(byte v, int bitNo)108 private static boolean bitSet(byte v, int bitNo) 109 { 110 return (v & (1 << bitNo)) != 0; 111 } 112 } 113