| package org.bouncycastle.crypto.macs; |
| |
| import org.bouncycastle.crypto.CipherParameters; |
| import org.bouncycastle.crypto.DataLengthException; |
| import org.bouncycastle.crypto.Mac; |
| import org.bouncycastle.crypto.params.KeyParameter; |
| import org.bouncycastle.crypto.params.ParametersWithIV; |
| |
| public class VMPCMac implements Mac |
| { |
| private byte g; |
| |
| private byte n = 0; |
| private byte[] P = null; |
| private byte s = 0; |
| |
| private byte[] T; |
| private byte[] workingIV; |
| |
| private byte[] workingKey; |
| |
| private byte x1, x2, x3, x4; |
| |
| public int doFinal(byte[] out, int outOff) |
| throws DataLengthException, IllegalStateException |
| { |
| // Execute the Post-Processing Phase |
| for (int r = 1; r < 25; r++) |
| { |
| s = P[(s + P[n & 0xff]) & 0xff]; |
| |
| x4 = P[(x4 + x3 + r) & 0xff]; |
| x3 = P[(x3 + x2 + r) & 0xff]; |
| x2 = P[(x2 + x1 + r) & 0xff]; |
| x1 = P[(x1 + s + r) & 0xff]; |
| T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1); |
| T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2); |
| T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3); |
| T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4); |
| g = (byte) ((g + 4) & 0x1f); |
| |
| byte temp = P[n & 0xff]; |
| P[n & 0xff] = P[s & 0xff]; |
| P[s & 0xff] = temp; |
| n = (byte) ((n + 1) & 0xff); |
| } |
| |
| // Input T to the IV-phase of the VMPC KSA |
| for (int m = 0; m < 768; m++) |
| { |
| s = P[(s + P[m & 0xff] + T[m & 0x1f]) & 0xff]; |
| byte temp = P[m & 0xff]; |
| P[m & 0xff] = P[s & 0xff]; |
| P[s & 0xff] = temp; |
| } |
| |
| // Store 20 new outputs of the VMPC Stream Cipher in table M |
| byte[] M = new byte[20]; |
| for (int i = 0; i < 20; i++) |
| { |
| s = P[(s + P[i & 0xff]) & 0xff]; |
| M[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff]; |
| |
| byte temp = P[i & 0xff]; |
| P[i & 0xff] = P[s & 0xff]; |
| P[s & 0xff] = temp; |
| } |
| |
| System.arraycopy(M, 0, out, outOff, M.length); |
| reset(); |
| |
| return M.length; |
| } |
| |
| public String getAlgorithmName() |
| { |
| return "VMPC-MAC"; |
| } |
| |
| public int getMacSize() |
| { |
| return 20; |
| } |
| |
| public void init(CipherParameters params) throws IllegalArgumentException |
| { |
| if (!(params instanceof ParametersWithIV)) |
| { |
| throw new IllegalArgumentException( |
| "VMPC-MAC Init parameters must include an IV"); |
| } |
| |
| ParametersWithIV ivParams = (ParametersWithIV) params; |
| KeyParameter key = (KeyParameter) ivParams.getParameters(); |
| |
| if (!(ivParams.getParameters() instanceof KeyParameter)) |
| { |
| throw new IllegalArgumentException( |
| "VMPC-MAC Init parameters must include a key"); |
| } |
| |
| this.workingIV = ivParams.getIV(); |
| |
| if (workingIV == null || workingIV.length < 1 || workingIV.length > 768) |
| { |
| throw new IllegalArgumentException( |
| "VMPC-MAC requires 1 to 768 bytes of IV"); |
| } |
| |
| this.workingKey = key.getKey(); |
| |
| reset(); |
| |
| } |
| |
| private void initKey(byte[] keyBytes, byte[] ivBytes) |
| { |
| s = 0; |
| P = new byte[256]; |
| for (int i = 0; i < 256; i++) |
| { |
| P[i] = (byte) i; |
| } |
| for (int m = 0; m < 768; m++) |
| { |
| s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.length]) & 0xff]; |
| byte temp = P[m & 0xff]; |
| P[m & 0xff] = P[s & 0xff]; |
| P[s & 0xff] = temp; |
| } |
| for (int m = 0; m < 768; m++) |
| { |
| s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.length]) & 0xff]; |
| byte temp = P[m & 0xff]; |
| P[m & 0xff] = P[s & 0xff]; |
| P[s & 0xff] = temp; |
| } |
| n = 0; |
| } |
| |
| public void reset() |
| { |
| initKey(this.workingKey, this.workingIV); |
| g = x1 = x2 = x3 = x4 = n = 0; |
| T = new byte[32]; |
| for (int i = 0; i < 32; i++) |
| { |
| T[i] = 0; |
| } |
| } |
| |
| public void update(byte in) throws IllegalStateException |
| { |
| s = P[(s + P[n & 0xff]) & 0xff]; |
| byte c = (byte) (in ^ P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff]); |
| |
| x4 = P[(x4 + x3) & 0xff]; |
| x3 = P[(x3 + x2) & 0xff]; |
| x2 = P[(x2 + x1) & 0xff]; |
| x1 = P[(x1 + s + c) & 0xff]; |
| T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1); |
| T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2); |
| T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3); |
| T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4); |
| g = (byte) ((g + 4) & 0x1f); |
| |
| byte temp = P[n & 0xff]; |
| P[n & 0xff] = P[s & 0xff]; |
| P[s & 0xff] = temp; |
| n = (byte) ((n + 1) & 0xff); |
| } |
| |
| public void update(byte[] in, int inOff, int len) |
| throws DataLengthException, IllegalStateException |
| { |
| if ((inOff + len) > in.length) |
| { |
| throw new DataLengthException("input buffer too short"); |
| } |
| |
| for (int i = 0; i < len; i++) |
| { |
| update(in[inOff + i]); |
| } |
| } |
| } |