1 16 17 package de.schlichtherle.crypto.io.raes; 18 19 import de.schlichtherle.crypto.SeekableBlockCipher; 20 import de.schlichtherle.crypto.modes.SICSeekableBlockCipher; 21 import de.schlichtherle.io.rof.FilterReadOnlyFile; 22 import de.schlichtherle.io.rof.ReadOnlyFile; 23 import de.schlichtherle.util.Arrays; 24 25 import java.io.FileNotFoundException ; 26 import java.io.IOException ; 27 28 import org.bouncycastle.crypto.CipherParameters; 29 import org.bouncycastle.crypto.Digest; 30 import org.bouncycastle.crypto.Mac; 31 import org.bouncycastle.crypto.PBEParametersGenerator; 32 import org.bouncycastle.crypto.digests.SHA256Digest; 33 import org.bouncycastle.crypto.engines.AESFastEngine; 34 import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; 35 import org.bouncycastle.crypto.macs.HMac; 36 import org.bouncycastle.crypto.params.KeyParameter; 37 import org.bouncycastle.crypto.params.ParametersWithIV; 38 39 46 class Type0RaesReadOnlyFile extends RaesReadOnlyFile { 47 48 52 private static final long MIN_KEY_RETRY_DELAY = 3 * 1000; 53 54 55 private final int keyStrength; 56 57 60 private final CipherParameters macParam; 61 62 65 private final byte[] footer; 66 67 Type0RaesReadOnlyFile( 68 final ReadOnlyFile rof, 69 final Type0RaesParameters parameters) 70 throws NullPointerException , 71 FileNotFoundException , 72 RaesException, 73 RaesKeyException, 74 IOException { 75 super(rof); 76 77 assert rof != null; 78 assert parameters != null; 79 80 final byte[] header = new byte[ENVELOPE_TYPE_0_HEADER_LEN_WO_SALT]; 82 final long fileLength = rof.length(); 83 rof.seek(0); 84 rof.readFully(header); 85 86 keyStrength = parseUByte(header, 5); 88 if (keyStrength != Type0RaesParameters.KEY_STRENGTH_128 89 && keyStrength != Type0RaesParameters.KEY_STRENGTH_192 90 && keyStrength != Type0RaesParameters.KEY_STRENGTH_256) 91 throw new RaesException( 92 "Unknown index for cipher key strength: " 93 + keyStrength 94 + "!"); 95 final int keyLen = 16 + keyStrength * 8; final int keySize = keyLen * 8; final int iCount = parseUShort(header, 6); 98 if (iCount < 1024) 99 throw new RaesException( 100 "Iteration count must be 1024 or greater, but is " 101 + iCount 102 + "!"); 103 104 final long start = header.length + keyLen; 106 107 final byte[] salt = new byte[keyLen]; 109 rof.readFully(salt); 110 111 final Digest digest = new SHA256Digest(); 113 114 footer = new byte[digest.getDigestSize()]; 116 final long end = fileLength - footer.length; 117 rof.seek(end); 118 rof.readFully(footer); 119 if (this.rof.read() != -1) { 120 throw new RaesException( 123 "Expected end of file after data envelope trailer!"); 124 } 125 126 final long length = fileLength - footer.length - start; 128 129 final PBEParametersGenerator paramGen 131 = new PKCS12ParametersGenerator(digest); 132 ParametersWithIV cipherParam; 133 CipherParameters macParam; 134 long lastTry = 0; while (true) { 136 final char[] passwd = parameters.getOpenPasswd(); 137 if (passwd == null) throw new RaesKeyException(); 139 final byte[] pass 140 = PBEParametersGenerator.PKCS12PasswordToBytes(passwd); 141 for (int i = passwd.length; --i >= 0; ) passwd[i] = 0; 143 144 paramGen.init(pass, salt, iCount); 145 cipherParam 146 = (ParametersWithIV) paramGen.generateDerivedParameters( 147 keySize, AES_BLOCK_SIZE); 148 macParam = paramGen.generateDerivedMacParameters(keySize); 149 for (int i = pass.length; --i >= 0; ) pass[i] = 0; 151 152 final Mac klac = new HMac(digest); 154 klac.init(macParam); 155 final byte[] cipherKey 156 = ((KeyParameter) cipherParam.getParameters()).getKey(); 157 klac.update(cipherKey, 0, cipherKey.length); 158 final byte[] buf = new byte[klac.getMacSize()]; 159 RaesOutputStream.klac(klac, length, buf); 160 digest.reset(); 162 lastTry = enforceSuspensionPenalty(lastTry); 163 164 if (Arrays.equals(footer, 0, buf, 0, buf.length / 2)) { 165 parameters.setKeyStrength(keyStrength); 166 break; 167 } 168 169 parameters.invalidOpenPasswd(); 170 } 171 172 this.macParam = macParam; 173 174 final SeekableBlockCipher cipher = new SICSeekableBlockCipher(new AESFastEngine()); 176 cipher.init(false, cipherParam); 177 178 init(cipher, start, length); 179 } 180 181 private static long enforceSuspensionPenalty(final long last) { 182 long delay; 183 InterruptedException interrupted = null; 184 while ((delay = System.currentTimeMillis() - last) < MIN_KEY_RETRY_DELAY) { 185 try { 186 Thread.sleep(MIN_KEY_RETRY_DELAY - delay); 187 } catch (InterruptedException ex) { 188 interrupted = ex; 189 } 190 } 191 if (interrupted != null) 192 Thread.currentThread().interrupt(); 193 return last + delay; 194 } 195 196 public int getKeySizeBits() { 197 return 128 + keyStrength * 64; 198 } 199 200 public void authenticate() 201 throws RaesAuthenticationException, IOException { 202 final Mac mac = new HMac(new SHA256Digest()); 203 mac.init(macParam); 204 205 final byte[] buf = computeMac(mac); 206 207 if (!Arrays.equals(footer, footer.length / 2, buf, 0, buf.length / 2)) 208 throw new RaesAuthenticationException(); 209 } 210 } 211 | Popular Tags |