1 package org.bouncycastle.crypto.engines;
2 
3 import org.bouncycastle.crypto.CipherParameters;
4 import org.bouncycastle.crypto.InvalidCipherTextException;
5 import org.bouncycastle.crypto.Wrapper;
6 import org.bouncycastle.crypto.macs.GOST28147Mac;
7 import org.bouncycastle.crypto.params.ParametersWithIV;
8 import org.bouncycastle.crypto.params.ParametersWithRandom;
9 import org.bouncycastle.crypto.params.ParametersWithUKM;
10 import org.bouncycastle.util.Arrays;
11 
12 public class GOST28147WrapEngine
13     implements Wrapper
14 {
15     private GOST28147Engine cipher = new GOST28147Engine();
16     private GOST28147Mac mac = new GOST28147Mac();
17 
init(boolean forWrapping, CipherParameters param)18     public void init(boolean forWrapping, CipherParameters param)
19     {
20         if (param instanceof ParametersWithRandom)
21         {
22             ParametersWithRandom pr = (ParametersWithRandom)param;
23             param = pr.getParameters();
24         }
25 
26         ParametersWithUKM pU = (ParametersWithUKM)param;
27 
28         cipher.init(forWrapping, pU.getParameters());
29 
30         mac.init(new ParametersWithIV(pU.getParameters(), pU.getUKM()));
31     }
32 
getAlgorithmName()33     public String getAlgorithmName()
34     {
35         return "GOST28147Wrap";
36     }
37 
wrap(byte[] input, int inOff, int inLen)38     public byte[] wrap(byte[] input, int inOff, int inLen)
39     {
40         mac.update(input, inOff, inLen);
41 
42         byte[] wrappedKey = new byte[inLen + mac.getMacSize()];
43 
44         cipher.processBlock(input, inOff, wrappedKey, 0);
45         cipher.processBlock(input, inOff + 8, wrappedKey, 8);
46         cipher.processBlock(input, inOff + 16, wrappedKey, 16);
47         cipher.processBlock(input, inOff + 24, wrappedKey, 24);
48 
49         mac.doFinal(wrappedKey, inLen);
50 
51         return wrappedKey;
52     }
53 
unwrap(byte[] input, int inOff, int inLen)54     public byte[] unwrap(byte[] input, int inOff, int inLen)
55         throws InvalidCipherTextException
56     {
57         byte[] decKey = new byte[inLen - mac.getMacSize()];
58 
59         cipher.processBlock(input, inOff, decKey, 0);
60         cipher.processBlock(input, inOff + 8, decKey, 8);
61         cipher.processBlock(input, inOff + 16, decKey, 16);
62         cipher.processBlock(input, inOff + 24, decKey, 24);
63 
64         byte[] macResult = new byte[mac.getMacSize()];
65 
66         mac.update(decKey, 0, decKey.length);
67 
68         mac.doFinal(macResult, 0);
69 
70         byte[] macExpected = new byte[mac.getMacSize()];
71 
72         System.arraycopy(input, inOff + inLen - 4, macExpected, 0, mac.getMacSize());
73 
74         if (!Arrays.constantTimeAreEqual(macResult, macExpected))
75         {
76             throw new IllegalStateException("mac mismatch");
77         }
78 
79         return decKey;
80     }
81 }
82