aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/core/src/main/java/org/spongycastle/crypto/modes/GCFBBlockCipher.java
blob: 41e26fc1703011b94a9b1d06c3b865d0fac2cdac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package org.spongycastle.crypto.modes;

import org.spongycastle.crypto.BlockCipher;
import org.spongycastle.crypto.CipherParameters;
import org.spongycastle.crypto.DataLengthException;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
import org.spongycastle.crypto.params.ParametersWithRandom;
import org.spongycastle.crypto.params.ParametersWithSBox;

/**
 * An implementation of the GOST CFB mode with CryptoPro key meshing as described in RFC 4357.
 */
public class GCFBBlockCipher
    implements BlockCipher
{
    private static final byte[] C =
        {
            0x69, 0x00, 0x72, 0x22, 0x64, (byte)0xC9, 0x04, 0x23,
            (byte)0x8D, 0x3A, (byte)0xDB, (byte)0x96, 0x46, (byte)0xE9, 0x2A, (byte)0xC4,
            0x18, (byte)0xFE, (byte)0xAC, (byte)0x94, 0x00, (byte)0xED, 0x07, 0x12,
            (byte)0xC0, (byte)0x86, (byte)0xDC, (byte)0xC2, (byte)0xEF, 0x4C, (byte)0xA9, 0x2B
        };

    private final CFBBlockCipher cfbEngine;

    private KeyParameter key;
    private long         counter = 0;
    private boolean      forEncryption;

    public GCFBBlockCipher(BlockCipher engine)
    {
        this.cfbEngine = new CFBBlockCipher(engine, engine.getBlockSize() * 8);
    }

    public void init(boolean forEncryption, CipherParameters params)
        throws IllegalArgumentException
    {
        counter = 0;
        cfbEngine.init(forEncryption, params);

        this.forEncryption = forEncryption;

        if (params instanceof ParametersWithIV)
        {
            params = ((ParametersWithIV)params).getParameters();
        }

        if (params instanceof ParametersWithRandom)
        {
            params = ((ParametersWithRandom)params).getParameters();
        }

        if (params instanceof ParametersWithSBox)
        {
            params = ((ParametersWithSBox)params).getParameters();
        }

        key = (KeyParameter)params;
    }

    public String getAlgorithmName()
    {
        return "G" + cfbEngine.getAlgorithmName();
    }

    public int getBlockSize()
    {
        return cfbEngine.getBlockSize();
    }

    public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
        throws DataLengthException, IllegalStateException
    {
        if (counter > 0 && counter % 1024 == 0)
        {
            BlockCipher  base = cfbEngine.getUnderlyingCipher();

            base.init(false, key);

            byte[] nextKey = new byte[32];

            base.processBlock(C, 0, nextKey, 0);
            base.processBlock(C, 8, nextKey, 8);
            base.processBlock(C, 16, nextKey, 16);
            base.processBlock(C, 24, nextKey, 24);

            key = new KeyParameter(nextKey);

            byte[] iv = new byte[8];

            base.init(true, key);

            base.processBlock(cfbEngine.getCurrentIV(), 0, iv, 0);

            cfbEngine.init(forEncryption, new ParametersWithIV(key, iv));
        }

        counter += cfbEngine.getBlockSize();

        return cfbEngine.processBlock(in, inOff, out, outOff);
    }

    public void reset()
    {
        counter = 0;
        cfbEngine.reset();
    }
}