Welcome to mirror list, hosted at ThFree Co, Russian Federation.

Shacal2Engine.java « engines « crypto « spongycastle « org « java « main « src « core - gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 8b461f86ad5ced5fc057818c6aedf80962f21230 (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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package org.spongycastle.crypto.engines;

import org.spongycastle.crypto.BlockCipher;
import org.spongycastle.crypto.CipherParameters;
import org.spongycastle.crypto.DataLengthException;
import org.spongycastle.crypto.OutputLengthException;
import org.spongycastle.crypto.params.KeyParameter;

/**
 * Block cipher Shacal2, designed by Helena Handschuh and David Naccache,
 * based on hash function SHA-256,
 * using SHA-256-Initialization-Values as data and SHA-256-Data as key.
 * <p>
 * A description of Shacal can be found at:
 *    http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.3.4066
 * Best known cryptanalytic (Wikipedia 11.2013):
 *    Related-key rectangle attack on 44-rounds (Jiqiang Lu, Jongsung Kim).
 * Comments are related to SHA-256-Naming as described in FIPS PUB 180-2
 * </p>
 */
public class Shacal2Engine 
	implements BlockCipher 
{
	private final static int[] K = { // SHA-256-Constants
			0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 
			0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 
			0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 
			0x983e5152,	0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 
			0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,	0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 
			0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 
			0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 
			0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,	0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 
	}; 
	
	private static final int BLOCK_SIZE = 32;
	private boolean forEncryption = false;
	private static final int ROUNDS = 64;
	
	private int[] workingKey = null; // expanded key: corresponds to the message block W in FIPS PUB 180-2
	
	public Shacal2Engine()
	{		
	}
	
	public void reset()
	{
	}
	
	public String getAlgorithmName()
	{
		return "Shacal2";
	}

	public int getBlockSize()
	{
	    return BLOCK_SIZE;
	}

	public void init(boolean _forEncryption, CipherParameters  params)
		throws IllegalArgumentException
	{
		if (!(params instanceof KeyParameter))
		{
			throw new IllegalArgumentException("only simple KeyParameter expected.");
		}
		this.forEncryption = _forEncryption;
		workingKey = new int[64];
		setKey( ((KeyParameter)params).getKey() );
	}

	public void setKey(byte[] kb) 
	{
		if (kb.length == 0 || kb.length > 64 || kb.length < 16 || kb.length % 8 != 0)
		{
			throw new IllegalArgumentException("Shacal2-key must be 16 - 64 bytes and multiple of 8");
		}

		bytes2ints(kb, workingKey, 0, 0);

		for ( int i = 16; i < 64; i++) 
		{ // Key-Expansion, implicitly Zero-Padding for 16 > i > kb.length/4
			workingKey[i] = 
									( (workingKey[i-2] >>> 17 | workingKey[i-2] << -17) // corresponds to ROTL n(x) of FIPS PUB 180-2
										^ (workingKey[i-2] >>> 19 | workingKey[i-2] << -19)
										^ (workingKey[i-2] >>> 10) ) // corresponds to sigma1(x)-Function of FIPS PUB 180-2	    	  
									+ workingKey[i-7] 		    				
									+ ( (workingKey[i-15] >>> 7 | workingKey[i-15] << -7) 
										^ (workingKey[i-15] >>> 18 | workingKey[i-15] << -18) 
										^ (workingKey[i-15] >>> 3) ) // corresponds to sigma0(x)-Function of FIPS PUB 180-2	    
									+ workingKey[i-16];
		}
	}
	
	public void encryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) 
	{
		int[] block = new int[BLOCK_SIZE / 4];// corresponds to working variables a,b,c,d,e,f,g,h of FIPS PUB 180-2
		bytes2ints(in, block, inOffset, 0);
		
		for (int i = 0; i < ROUNDS; i++) 
		{			
			int tmp =
                (((block[4] >>> 6) | (block[4] << -6))
                    ^ ((block[4] >>> 11) | (block[4] << -11))
                    ^ ((block[4] >>> 25) | (block[4] << -25)))
                    + ((block[4] & block[5]) ^ ((~block[4]) & block[6]))
                    + block[7] + K[i] + workingKey[i];  // corresponds to T1 of FIPS PUB 180-2
			block[7] = block[6];
			block[6] = block[5];
			block[5] = block[4];			
			block[4] = block[3] + tmp;
			block[3] = block[2];
			block[2] = block[1];
			block[1] = block[0];
			block[0] = tmp
                + (((block[0] >>> 2) | (block[0] << -2))
                ^ ((block[0] >>> 13) | (block[0] << -13))
                ^ ((block[0] >>> 22) | (block[0] << -22)))
                + ((block[0] & block[2]) ^ (block[0] & block[3]) ^ (block[2] & block[3]));
			//corresponds to T2 of FIPS PUB 180-2, block[1] and block[2] replaced
		}		
		ints2bytes(block, out, outOffset);
	}
	
	public void decryptBlock(byte[] in, int inOffset, byte[] out, int outOffset) 
	{		
		int[] block = new int[BLOCK_SIZE / 4];
		bytes2ints(in, block, inOffset, 0);		
		for (int i = ROUNDS - 1; i >-1; i--) 
		{
            int tmp = block[0] - (((block[1] >>> 2) | (block[1] << -2))
                ^ ((block[1] >>> 13) | (block[1] << -13))
                ^ ((block[1] >>> 22) | (block[1] << -22)))
                - ((block[1] & block[2]) ^ (block[1] & block[3]) ^ (block[2] & block[3]));    // T2
            block[0] = block[1];
            block[1] = block[2];
            block[2] = block[3];
            block[3] = block[4] - tmp;
            block[4] = block[5];
            block[5] = block[6];
            block[6] = block[7];
            block[7] = tmp - K[i] - workingKey[i]
                - (((block[4] >>> 6) | (block[4] << -6))
                ^ ((block[4] >>> 11) | (block[4] << -11))
                ^ ((block[4] >>> 25) | (block[4] << -25)))
                - ((block[4] & block[5]) ^ ((~block[4]) & block[6])); // T1
        }
		ints2bytes(block, out, outOffset);
	}

	public int processBlock(byte[] in, int inOffset, byte[] out, int outOffset)	    
			throws DataLengthException, IllegalStateException 
	{
		if (workingKey == null)
		{
			throw new IllegalStateException("Shacal2 not initialised");
		}

		if ((inOffset + BLOCK_SIZE) > in.length)
		{
			throw new DataLengthException("input buffer too short");
		}

		if ((outOffset + BLOCK_SIZE) > out.length)
		{
			throw new OutputLengthException("output buffer too short");
		}

		if (forEncryption)
		{
			encryptBlock(in, inOffset, out, outOffset);
		}
		else
		{    
			decryptBlock(in, inOffset, out, outOffset);
		}

		return BLOCK_SIZE;
	}

    private void bytes2ints(byte[] bytes, int[] block, int bytesPos, int blockPos)
    {
        for (int i = blockPos; i < bytes.length / 4; i++)
        {
            block[i] = ((bytes[bytesPos++] & 0xFF) << 24)
                | ((bytes[bytesPos++] & 0xFF) << 16)
                | ((bytes[bytesPos++] & 0xFF) << 8)
                | (bytes[bytesPos++] & 0xFF);
        }
    }

    private void ints2bytes(int[] block, byte[] out, int pos)
    {
        for (int i = 0; i < block.length; i++)
        {
            out[pos++] = (byte)(block[i] >>> 24);
            out[pos++] = (byte)(block[i] >>> 16);
            out[pos++] = (byte)(block[i] >>> 8);
            out[pos++] = (byte)block[i];
        }
    }
}