AESWrapEngine.java revision b61a96e7ef1a78acf013bbf08fe537e5b5f129ca
1package org.bouncycastle.crypto.engines; 2 3import org.bouncycastle.crypto.BlockCipher; 4import org.bouncycastle.crypto.CipherParameters; 5import org.bouncycastle.crypto.DataLengthException; 6import org.bouncycastle.crypto.InvalidCipherTextException; 7import org.bouncycastle.crypto.Wrapper; 8import org.bouncycastle.crypto.params.KeyParameter; 9import org.bouncycastle.crypto.params.ParametersWithIV; 10 11/** 12 * an implementation of the AES Key Wrapper from the NIST Key Wrap 13 * Specification. 14 * <p> 15 * For further details see: <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>. 16 */ 17public class AESWrapEngine 18 implements Wrapper 19{ 20 private BlockCipher engine = new AESEngine(); 21 private KeyParameter param; 22 private boolean forWrapping; 23 24 private byte[] iv = { 25 (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6, 26 (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6 }; 27 28 public void init( 29 boolean forWrapping, 30 CipherParameters param) 31 { 32 this.forWrapping = forWrapping; 33 34 if (param instanceof KeyParameter) 35 { 36 this.param = (KeyParameter)param; 37 } 38 else if (param instanceof ParametersWithIV) 39 { 40 this.iv = ((ParametersWithIV) param).getIV(); 41 this.param = (KeyParameter) ((ParametersWithIV) param).getParameters(); 42 if (this.iv.length != 8) 43 { 44 throw new IllegalArgumentException("IV not multiple of 8"); 45 } 46 } 47 } 48 49 public String getAlgorithmName() 50 { 51 return "AES"; 52 } 53 54 public byte[] wrap( 55 byte[] in, 56 int inOff, 57 int inLen) 58 { 59 if (!forWrapping) 60 { 61 throw new IllegalStateException("not set for wrapping"); 62 } 63 64 int n = inLen / 8; 65 66 if ((n * 8) != inLen) 67 { 68 throw new DataLengthException("wrap data must be a multiple of 8 bytes"); 69 } 70 71 byte[] block = new byte[inLen + iv.length]; 72 byte[] buf = new byte[8 + iv.length]; 73 74 System.arraycopy(iv, 0, block, 0, iv.length); 75 System.arraycopy(in, 0, block, iv.length, inLen); 76 77 engine.init(true, param); 78 79 for (int j = 0; j != 6; j++) 80 { 81 for (int i = 1; i <= n; i++) 82 { 83 System.arraycopy(block, 0, buf, 0, iv.length); 84 System.arraycopy(block, 8 * i, buf, iv.length, 8); 85 engine.processBlock(buf, 0, buf, 0); 86 87 int t = n * j + i; 88 for (int k = 1; t != 0; k++) 89 { 90 byte v = (byte)t; 91 92 buf[iv.length - k] ^= v; 93 94 t >>>= 8; 95 } 96 97 System.arraycopy(buf, 0, block, 0, 8); 98 System.arraycopy(buf, 8, block, 8 * i, 8); 99 } 100 } 101 102 return block; 103 } 104 105 public byte[] unwrap( 106 byte[] in, 107 int inOff, 108 int inLen) 109 throws InvalidCipherTextException 110 { 111 if (forWrapping) 112 { 113 throw new IllegalStateException("not set for unwrapping"); 114 } 115 116 int n = inLen / 8; 117 118 if ((n * 8) != inLen) 119 { 120 throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes"); 121 } 122 123 byte[] block = new byte[inLen - iv.length]; 124 byte[] a = new byte[iv.length]; 125 byte[] buf = new byte[8 + iv.length]; 126 127 System.arraycopy(in, 0, a, 0, iv.length); 128 System.arraycopy(in, iv.length, block, 0, inLen - iv.length); 129 130 engine.init(false, param); 131 132 n = n - 1; 133 134 for (int j = 5; j >= 0; j--) 135 { 136 for (int i = n; i >= 1; i--) 137 { 138 System.arraycopy(a, 0, buf, 0, iv.length); 139 System.arraycopy(block, 8 * (i - 1), buf, iv.length, 8); 140 141 int t = n * j + i; 142 for (int k = 1; t != 0; k++) 143 { 144 byte v = (byte)t; 145 146 buf[iv.length - k] ^= v; 147 148 t >>>= 8; 149 } 150 151 engine.processBlock(buf, 0, buf, 0); 152 System.arraycopy(buf, 0, a, 0, 8); 153 System.arraycopy(buf, 8, block, 8 * (i - 1), 8); 154 } 155 } 156 157 for (int i = 0; i != iv.length; i++) 158 { 159 if (a[i] != iv[i]) 160 { 161 throw new InvalidCipherTextException("checksum failed"); 162 } 163 } 164 165 return block; 166 } 167} 168