1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage org.bouncycastle.crypto.engines; 2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.SecureRandom; 4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.CipherParameters; 6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.Digest; 7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.InvalidCipherTextException; 8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.Wrapper; 9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.digests.SHA1Digest; 10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.modes.CBCBlockCipher; 11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.params.KeyParameter; 12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.bouncycastle.crypto.params.ParametersWithIV; 13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/** 15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Wrap keys according to 16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-smime-key-wrap-01.txt"> 17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * draft-ietf-smime-key-wrap-01.txt</A>. 18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <p> 19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Note: 20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <ul> 21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <li>this is based on a draft, and as such is subject to change - don't use this class for anything requiring long term storage. 22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <li>if you are using this to wrap triple-des keys you need to set the 23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * parity bits on the key and, if it's a two-key triple-des key, pad it 24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * yourself. 25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * </ul> 26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class DESedeWrapEngine 28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project implements Wrapper 29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{ 30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** Field engine */ 31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private CBCBlockCipher engine; 32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** Field param */ 34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private KeyParameter param; 35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** Field paramPlusIV */ 37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private ParametersWithIV paramPlusIV; 38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** Field iv */ 40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private byte[] iv; 41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** Field forWrapping */ 43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private boolean forWrapping; 44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** Field IV2 */ 46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private static final byte[] IV2 = { (byte) 0x4a, (byte) 0xdd, (byte) 0xa2, 47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (byte) 0x2c, (byte) 0x79, (byte) 0xe8, 48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project (byte) 0x21, (byte) 0x05 }; 49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // 51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // checksum digest 52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // 53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Digest sha1 = new SHA1Digest(); 54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] digest = new byte[20]; 55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Method init 58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param forWrapping 60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param param 61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public void init(boolean forWrapping, CipherParameters param) 63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.forWrapping = forWrapping; 66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.engine = new CBCBlockCipher(new DESedeEngine()); 67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (param instanceof KeyParameter) 69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.param = (KeyParameter)param; 71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (this.forWrapping) 73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Hm, we have no IV but we want to wrap ?!? 76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // well, then we have to create our own IV. 77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.iv = new byte[8]; 78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project SecureRandom sr = new SecureRandom(); 80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project sr.nextBytes(iv); 82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.paramPlusIV = new ParametersWithIV(this.param, this.iv); 84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project else if (param instanceof ParametersWithIV) 87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.paramPlusIV = (ParametersWithIV)param; 89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.iv = this.paramPlusIV.getIV(); 90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.param = (KeyParameter)this.paramPlusIV.getParameters(); 91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (this.forWrapping) 93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if ((this.iv == null) || (this.iv.length != 8)) 95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new IllegalArgumentException("IV is not 8 octets"); 97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project else 100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new IllegalArgumentException( 102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "You should not supply an IV for unwrapping"); 103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Method getAlgorithmName 109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @return the algorithm name "DESede". 111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public String getAlgorithmName() 113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return "DESede"; 115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Method wrap 119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param in 121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param inOff 122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param inLen 123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @return the wrapped bytes. 124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public byte[] wrap(byte[] in, int inOff, int inLen) 126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!forWrapping) 128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new IllegalStateException("Not initialized for wrapping"); 130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte keyToBeWrapped[] = new byte[inLen]; 133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.arraycopy(in, inOff, keyToBeWrapped, 0, inLen); 135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Compute the CMS Key Checksum, (section 5.6.1), call this CKS. 137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] CKS = calculateCMSKeyChecksum(keyToBeWrapped); 138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Let WKCKS = WK || CKS where || is concatenation. 140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] WKCKS = new byte[keyToBeWrapped.length + CKS.length]; 141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.arraycopy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.length); 143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.arraycopy(CKS, 0, WKCKS, keyToBeWrapped.length, CKS.length); 144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Encrypt WKCKS in CBC mode using KEK as the key and IV as the 146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // initialization vector. Call the results TEMP1. 147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte TEMP1[] = new byte[WKCKS.length]; 148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.arraycopy(WKCKS, 0, TEMP1, 0, WKCKS.length); 150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int noOfBlocks = WKCKS.length / engine.getBlockSize(); 152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int extraBytes = WKCKS.length % engine.getBlockSize(); 153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (extraBytes != 0) 155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new IllegalStateException("Not multiple of block length"); 157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project engine.init(true, paramPlusIV); 160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i = 0; i < noOfBlocks; i++) 162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int currentBytePos = i * engine.getBlockSize(); 164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project engine.processBlock(TEMP1, currentBytePos, TEMP1, currentBytePos); 166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Left TEMP2 = IV || TEMP1. 169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] TEMP2 = new byte[this.iv.length + TEMP1.length]; 170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.arraycopy(this.iv, 0, TEMP2, 0, this.iv.length); 172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.arraycopy(TEMP1, 0, TEMP2, this.iv.length, TEMP1.length); 173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Reverse the order of the octets in TEMP2 and call the result TEMP3. 175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] TEMP3 = new byte[TEMP2.length]; 176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i = 0; i < TEMP2.length; i++) 178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project TEMP3[i] = TEMP2[TEMP2.length - (i + 1)]; 180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Encrypt TEMP3 in CBC mode using the KEK and an initialization vector 183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired 184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // result. It is 40 octets long if a 168 bit key is being wrapped. 185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ParametersWithIV param2 = new ParametersWithIV(this.param, IV2); 186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.engine.init(true, param2); 188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i = 0; i < noOfBlocks + 1; i++) 190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int currentBytePos = i * engine.getBlockSize(); 192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project engine.processBlock(TEMP3, currentBytePos, TEMP3, currentBytePos); 194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return TEMP3; 197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Method unwrap 201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param in 203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param inOff 204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param inLen 205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @return the unwrapped bytes. 206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @throws InvalidCipherTextException 207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public byte[] unwrap(byte[] in, int inOff, int inLen) 209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throws InvalidCipherTextException 210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (forWrapping) 212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new IllegalStateException("Not set for unwrapping"); 214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (in == null) 217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new InvalidCipherTextException("Null pointer as ciphertext"); 219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (inLen % engine.getBlockSize() != 0) 222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new InvalidCipherTextException("Ciphertext not multiple of " 224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project + engine.getBlockSize()); 225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Check if the length of the cipher text is reasonable given the key 229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // type. It must be 40 bytes for a 168 bit key and either 32, 40, or 230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // 48 bytes for a 128, 192, or 256 bit key. If the length is not supported 231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // or inconsistent with the algorithm for which the key is intended, 232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // return error. 233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // 234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // we do not accept 168 bit keys. it has to be 192 bit. 235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int lengthA = (estimatedKeyLengthInBit / 8) + 16; 236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int lengthB = estimatedKeyLengthInBit % 8; 237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if ((lengthA != keyToBeUnwrapped.length) || (lengthB != 0)) { 239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new XMLSecurityException("empty"); 240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK 244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3. 245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ParametersWithIV param2 = new ParametersWithIV(this.param, IV2); 246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.engine.init(false, param2); 248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte TEMP3[] = new byte[inLen]; 250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.arraycopy(in, inOff, TEMP3, 0, inLen); 252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i = 0; i < (TEMP3.length / engine.getBlockSize()); i++) 254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int currentBytePos = i * engine.getBlockSize(); 256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project engine.processBlock(TEMP3, currentBytePos, TEMP3, currentBytePos); 258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Reverse the order of the octets in TEMP3 and call the result TEMP2. 261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] TEMP2 = new byte[TEMP3.length]; 262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i = 0; i < TEMP3.length; i++) 264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project TEMP2[i] = TEMP3[TEMP3.length - (i + 1)]; 266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets. 269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.iv = new byte[8]; 270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] TEMP1 = new byte[TEMP2.length - 8]; 272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.arraycopy(TEMP2, 0, this.iv, 0, 8); 274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.arraycopy(TEMP2, 8, TEMP1, 0, TEMP2.length - 8); 275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV 277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // found in the previous step. Call the result WKCKS. 278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.paramPlusIV = new ParametersWithIV(this.param, this.iv); 279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.engine.init(false, this.paramPlusIV); 281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] WKCKS = new byte[TEMP1.length]; 283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.arraycopy(TEMP1, 0, WKCKS, 0, TEMP1.length); 285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i = 0; i < (WKCKS.length / engine.getBlockSize()); i++) 287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int currentBytePos = i * engine.getBlockSize(); 289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project engine.processBlock(WKCKS, currentBytePos, WKCKS, currentBytePos); 291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Decompose WKCKS. CKS is the last 8 octets and WK, the wrapped key, are 294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // those octets before the CKS. 295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] result = new byte[WKCKS.length - 8]; 296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] CKStoBeVerified = new byte[8]; 297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.arraycopy(WKCKS, 0, result, 0, WKCKS.length - 8); 299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.arraycopy(WKCKS, WKCKS.length - 8, CKStoBeVerified, 0, 8); 300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare 302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // with the CKS extracted in the above step. If they are not equal, return error. 303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (!checkCMSKeyChecksum(result, CKStoBeVerified)) 304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new InvalidCipherTextException( 306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "Checksum inside ciphertext is corrupted"); 307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // WK is the wrapped key, now extracted for use in data decryption. 310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return result; 311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Some key wrap algorithms make use of the Key Checksum defined 315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * in CMS [CMS-Algorithms]. This is used to provide an integrity 316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * check value for the key being wrapped. The algorithm is 317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - Compute the 20 octet SHA-1 hash on the key being wrapped. 319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * - Use the first 8 octets of this hash as the checksum value. 320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param key 322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @return the CMS checksum. 323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @throws RuntimeException 324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum 325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private byte[] calculateCMSKeyChecksum( 327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] key) 328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] result = new byte[8]; 330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project sha1.update(key, 0, key.length); 332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project sha1.doFinal(digest, 0); 333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project System.arraycopy(digest, 0, result, 0, 8); 335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return result; 337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param key 341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param checksum 342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @return true if okay, false otherwise. 343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum 344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private boolean checkCMSKeyChecksum( 346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] key, 347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] checksum) 348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project byte[] calculatedChecksum = calculateCMSKeyChecksum(key); 350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (checksum.length != calculatedChecksum.length) 352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i = 0; i != checksum.length; i++) 357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (checksum[i] != calculatedChecksum[i]) 359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project { 360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return false; 361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return true; 365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 367