mirror of
https://github.com/brmlab/timingattack.git
synced 2025-12-16 00:13:59 +01:00
224 lines
No EOL
7 KiB
Java
224 lines
No EOL
7 KiB
Java
/*
|
|
* Copyright 2008 Google Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package cz.cvut.keyczar;
|
|
|
|
import com.google.gson.annotations.Expose;
|
|
|
|
import cz.cvut.keyczar.enums.CipherMode;
|
|
import cz.cvut.keyczar.enums.KeyType;
|
|
import cz.cvut.keyczar.exceptions.KeyczarException;
|
|
import cz.cvut.keyczar.exceptions.ShortBufferException;
|
|
import cz.cvut.keyczar.interfaces.DecryptingStream;
|
|
import cz.cvut.keyczar.interfaces.EncryptingStream;
|
|
import cz.cvut.keyczar.interfaces.SigningStream;
|
|
import cz.cvut.keyczar.interfaces.Stream;
|
|
import cz.cvut.keyczar.interfaces.VerifyingStream;
|
|
import cz.cvut.keyczar.util.Base64Coder;
|
|
import cz.cvut.keyczar.util.Util;
|
|
|
|
import java.nio.ByteBuffer;
|
|
import java.security.GeneralSecurityException;
|
|
import java.security.Key;
|
|
|
|
import javax.crypto.Cipher;
|
|
import javax.crypto.spec.IvParameterSpec;
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
|
|
/**
|
|
* Wrapping class for AES keys. Currently the default is to use CBC mode.
|
|
*
|
|
* @author steveweis@gmail.com (Steve Weis)
|
|
* @author arkajit.dey@gmail.com (Arkajit Dey)
|
|
*
|
|
*/
|
|
class AesKey extends KeyczarKey {
|
|
private Key aesKey;
|
|
private int blockSize;
|
|
|
|
private static final String AES_ALGORITHM = "AES";
|
|
private static final CipherMode DEFAULT_MODE = CipherMode.CBC;
|
|
|
|
@Expose private String aesKeyString = "";
|
|
@Expose private HmacKey hmacKey = new HmacKey();
|
|
@Expose private CipherMode mode = DEFAULT_MODE;
|
|
|
|
private byte[] hash = new byte[Keyczar.KEY_HASH_SIZE];
|
|
|
|
static AesKey generate() throws KeyczarException {
|
|
return generate(KeyType.AES.defaultSize());
|
|
}
|
|
|
|
static AesKey generate(int keySize) throws KeyczarException {
|
|
AesKey key = new AesKey();
|
|
key.size = keySize;
|
|
byte[] aesBytes = Util.rand(key.size() / 8);
|
|
key.aesKeyString = Base64Coder.encode(aesBytes);
|
|
key.mode = DEFAULT_MODE;
|
|
key.hmacKey = HmacKey.generate();
|
|
key.init();
|
|
return key;
|
|
}
|
|
|
|
@Override
|
|
KeyType getType() {
|
|
return KeyType.AES;
|
|
}
|
|
|
|
@Override
|
|
byte[] hash() {
|
|
return hash;
|
|
}
|
|
|
|
static AesKey read(String input) throws KeyczarException {
|
|
AesKey key = Util.gson().fromJson(input, AesKey.class);
|
|
key.hmacKey.init();
|
|
key.init();
|
|
return key;
|
|
}
|
|
|
|
private void init() throws KeyczarException {
|
|
byte[] aesBytes = Base64Coder.decode(aesKeyString);
|
|
aesKey = new SecretKeySpec(aesBytes, AES_ALGORITHM);
|
|
blockSize = aesBytes.length;
|
|
byte[] fullHash =
|
|
Util.hash(Util.fromInt(blockSize), aesBytes, hmacKey.keyBytes());
|
|
System.arraycopy(fullHash, 0, hash, 0, hash.length);
|
|
}
|
|
|
|
@Override
|
|
Stream getStream() throws KeyczarException {
|
|
return new AesStream();
|
|
}
|
|
|
|
private class AesStream implements EncryptingStream, DecryptingStream {
|
|
private Cipher encryptingCipher;
|
|
private Cipher decryptingCipher;
|
|
private SigningStream signStream;
|
|
boolean ivRead = false;
|
|
|
|
public AesStream() throws KeyczarException {
|
|
/*
|
|
* The JCE Cipher.init() call essentially reallocates a new Cipher object
|
|
* We avoid this by initializing two Cipher objects with zero-valued IVs,
|
|
* Then passing IVs for CBC mode ourselves. The Ciphers will be cached in
|
|
* this stream
|
|
*/
|
|
IvParameterSpec zeroIv = new IvParameterSpec(new byte[blockSize]);
|
|
try {
|
|
encryptingCipher = Cipher.getInstance(mode.getMode());
|
|
encryptingCipher.init(Cipher.ENCRYPT_MODE, aesKey, zeroIv);
|
|
decryptingCipher = Cipher.getInstance(mode.getMode());
|
|
decryptingCipher.init(Cipher.DECRYPT_MODE, aesKey, zeroIv);
|
|
signStream = (SigningStream) hmacKey.getStream();
|
|
} catch (GeneralSecurityException e) {
|
|
throw new KeyczarException(e);
|
|
}
|
|
}
|
|
|
|
public SigningStream getSigningStream() {
|
|
return signStream;
|
|
}
|
|
|
|
public VerifyingStream getVerifyingStream() {
|
|
return (VerifyingStream) signStream;
|
|
}
|
|
|
|
public void initDecrypt(ByteBuffer input) {
|
|
// This will simply decrypt the first block, leaving the CBC Cipher
|
|
// ready for the next block of input.
|
|
byte[] iv = new byte[blockSize];
|
|
input.get(iv);
|
|
decryptingCipher.update(iv);
|
|
ivRead = true;
|
|
}
|
|
|
|
public int initEncrypt(ByteBuffer output) throws KeyczarException {
|
|
// Generate a random value and encrypt it. This will be the IV.
|
|
byte[] ivPreImage = new byte[blockSize];
|
|
Util.rand(ivPreImage);
|
|
try {
|
|
return encryptingCipher.update(ByteBuffer.wrap(ivPreImage), output);
|
|
} catch (javax.crypto.ShortBufferException e) {
|
|
throw new ShortBufferException(e);
|
|
}
|
|
}
|
|
|
|
public int updateDecrypt(ByteBuffer input, ByteBuffer output)
|
|
throws KeyczarException {
|
|
if (ivRead && input.remaining() >= blockSize) {
|
|
// The next output block will be the IV preimage, which we'll discard
|
|
byte[] temp = new byte[blockSize];
|
|
input.get(temp);
|
|
decryptingCipher.update(temp); // discard IV preimage byte array
|
|
ivRead = false;
|
|
}
|
|
try {
|
|
return decryptingCipher.update(input, output);
|
|
} catch (javax.crypto.ShortBufferException e) {
|
|
throw new ShortBufferException(e);
|
|
}
|
|
}
|
|
|
|
public int updateEncrypt(ByteBuffer input, ByteBuffer output)
|
|
throws KeyczarException {
|
|
try {
|
|
return encryptingCipher.update(input, output);
|
|
} catch (javax.crypto.ShortBufferException e) {
|
|
throw new ShortBufferException(e);
|
|
}
|
|
}
|
|
|
|
public int doFinalDecrypt(ByteBuffer input, ByteBuffer output)
|
|
throws KeyczarException {
|
|
if (ivRead) {
|
|
if (input.remaining() == 0) {
|
|
// This can occur if someone encrypts an 0-length array
|
|
return 0;
|
|
}
|
|
// The next output block will be the IV preimage, which we'll discard
|
|
byte[] temp = new byte[blockSize];
|
|
input.get(temp);
|
|
decryptingCipher.update(temp); // discard IV preimage byte array
|
|
ivRead = false;
|
|
}
|
|
try {
|
|
if (input.remaining() == 0) {
|
|
byte[] outputBytes = decryptingCipher.doFinal();
|
|
output.put(outputBytes);
|
|
return outputBytes.length;
|
|
} else {
|
|
return decryptingCipher.doFinal(input, output);
|
|
}
|
|
} catch (GeneralSecurityException e) {
|
|
throw new KeyczarException(e);
|
|
}
|
|
}
|
|
|
|
public int doFinalEncrypt(ByteBuffer input, ByteBuffer output)
|
|
throws KeyczarException {
|
|
try {
|
|
return encryptingCipher.doFinal(input, output);
|
|
} catch (GeneralSecurityException e) {
|
|
throw new KeyczarException(e);
|
|
}
|
|
}
|
|
|
|
public int maxOutputSize(int inputLen) {
|
|
return mode.getOutputSize(blockSize, inputLen);
|
|
}
|
|
}
|
|
} |