Skip to content

Commit

Permalink
Merge pull request #1170 from herveyw/feature/cryptography
Browse files Browse the repository at this point in the history
Cryptography package updates
  • Loading branch information
jianghaolu committed Oct 7, 2016
2 parents fd0cc65 + 72f9cd1 commit 8909087
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,34 @@ public static void zero( byte[] self )
Arrays.fill(self, (byte)0);
}
}

/**
* Compares two byte arrays in constant time.
*
* @param self
* The first byte array to compare
* @param other
* The second byte array to compare
* @return
* True if the two byte arrays are equal.
*/
public static boolean sequenceEqualConstantTime( byte[] self, byte[] other )
{
if ( self == null )
throw new IllegalArgumentException( "self" );

if ( other == null )
throw new IllegalArgumentException( "other" );

// Constant time comparison of two byte arrays
long difference = ( self.length & 0xffffffffl ) ^ ( other.length & 0xffffffffl );

for ( int i = 0; i < self.length && i < other.length; i++ )
{
difference |= ( self[i] ^ other[i] ) & 0xffffffffl;
}

return difference == 0;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ protected SymmetricEncryptionAlgorithm(String name) {
* Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for encryption
* using the supplied initialization vector and the specific provider for the Java Security API.
* @param key
* The AES key material to be used.
* The key material to be used.
* @param iv
* The initialization vector to be used.
* @param authenticationData
* The authentication data to be used with authenticating encryption algorithms (optional)
* The authentication data to be used with authenticating encryption algorithms (ignored for non-authenticating algorithms)
* @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
Expand All @@ -49,11 +49,11 @@ protected SymmetricEncryptionAlgorithm(String name) {
* Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for encryption
* using the supplied initialization vector and the specific provider for the Java Security API.
* @param key
* The AES key material to be used.
* The key material to be used.
* @param iv
* The initialization vector to be used.
* @param authenticationData
* The authentication data to be used with authenticating encryption algorithms (optional)
* The authentication data to be used with authenticating encryption algorithms (ignored for non-authenticating algorithms)
* @param provider
* The provider to use.
* @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
Expand All @@ -68,28 +68,32 @@ protected SymmetricEncryptionAlgorithm(String name) {
* Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for decryption
* using the supplied initialization vector and the specific provider for the Java Security API.
* @param key
* The AES key material to be used.
* The key material to be used.
* @param iv
* The initialization vector to be used.
* @param authenticationData
* The authentication data to be used with authenticating encryption algorithms (optional)
* The authentication data to be used with authenticating encryption algorithms (ignored for non-authenticating algorithms)
* @param authenticationTag
* The authentication tag to verify when using authenticating encryption algorithms (ignored for non-authenticating algorithms)
* @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws InvalidAlgorithmParameterException
*/
public abstract ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException;
public abstract ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData, byte[] authenticationTag) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException;

/**
* Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for decryption
* using the supplied initialization vector and the specific provider for the Java Security API.
* @param key
* The AES key material to be used.
* The key material to be used.
* @param iv
* The initialization vector to be used.
* @param authenticationData
* The authentication data to be used with authenticating encryption algorithms (optional)
* The authentication data to be used with authenticating encryption algorithms (ignored for non-authenticating algorithms)
* @param authenticationTag
* The authentication tag to verify when using authenticating encryption algorithms (ignored for non-authenticating algorithms)
* @param provider
* The provider to use.
* @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
Expand All @@ -98,6 +102,6 @@ protected SymmetricEncryptionAlgorithm(String name) {
* @throws NoSuchPaddingException
* @throws InvalidAlgorithmParameterException
*/
public abstract ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException;
public abstract ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData, byte[] authenticationTag, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.SecureRandom;
import java.util.UUID;

import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
Expand All @@ -26,38 +29,121 @@
import com.microsoft.azure.keyvault.cryptography.algorithms.AesKw256;
import com.microsoft.azure.keyvault.cryptography.Strings;

/**
* A simple symmetric key implementation
*
*/
public class SymmetricKey implements IKey {

private static final SecureRandom Rng = new SecureRandom();

public static final int KeySize128 = 128 >> 3;
public static final int KeySize192 = 192 >> 3;
public static final int KeySize256 = 256 >> 3;
public static final int KeySize384 = 384 >> 3;
public static final int KeySize512 = 512 >> 3;

public static final int DefaultKeySize = KeySize256;

private final String _kid;
private final byte[] _key;
private final Provider _provider;

/**
* Creates a SymmetricKey with a random key identifier and
* a random key with DefaultKeySize bits.
*/
public SymmetricKey() {
this(UUID.randomUUID().toString());
}

/**
* Creates a SymmetricKey with the specified key identifier and
* a random key with DefaultKeySize bits.
* @param kid
* The key identifier to use.
*/
public SymmetricKey(String kid) {
this(kid, DefaultKeySize);
}

/**
* Creates a SymmetricKey with the specified key identifier and
* a random key with the specified size.
* @param kid
* The key identifier to use.
* @param keySizeInBytes
* The key size to use in bytes.
*/
public SymmetricKey(String kid, int keySizeInBytes ) {
this(kid, keySizeInBytes, null);
}

/**
* Creates a SymmetricKey with the specified key identifier and
* a random key with the specified size that uses the specified provider.
* @param kid
* The key identifier to use.
* @param keySizeInBytes
* The key size to use in bytes.
* @param provider
* The provider to use (optional, null for default)
*/
public SymmetricKey(String kid, int keySizeInBytes, Provider provider) {

if ( Strings.isNullOrWhiteSpace(kid) ) {
throw new IllegalArgumentException("kid");
}

if ( keySizeInBytes != KeySize128 && keySizeInBytes != KeySize192 && keySizeInBytes != KeySize256 && keySizeInBytes != KeySize384 && keySizeInBytes != KeySize512 ) {
throw new IllegalArgumentException("The key material must be 128, 192, 256, 384 or 512 bits of data");
}

_kid = kid;
_key = new byte[keySizeInBytes];
_provider = provider;

// Generate a random key
Rng.nextBytes(_key);
}

/**
* Creates a SymmetricKey with the specified key identifier and key material.
* @param kid
* The key identifier to use.
* @param keyBytes
* The key material to use.
*/
public SymmetricKey(String kid, byte[] keyBytes) {
this(kid, keyBytes, null);
}

/**
* Creates a SymmetricKey with the specified key identifier and key material
* that uses the specified Provider.
* @param kid
* The key identifier to use.
* @param keyBytes
* The key material to use.
* @param provider
* The Provider to use (optional, null for default)
*/
public SymmetricKey(String kid, byte[] keyBytes, Provider provider) {

if (Strings.isNullOrWhiteSpace(kid)) {
if ( Strings.isNullOrWhiteSpace(kid) ) {
throw new IllegalArgumentException("kid");
}

if (keyBytes == null) {
if ( keyBytes == null ) {
throw new IllegalArgumentException("keyBytes");
}

if (keyBytes.length != KeySize128 && keyBytes.length != KeySize192 && keyBytes.length != KeySize256 && keyBytes.length != KeySize384 && keyBytes.length != KeySize512) {
if ( keyBytes.length != KeySize128 && keyBytes.length != KeySize192 && keyBytes.length != KeySize256 && keyBytes.length != KeySize384 && keyBytes.length != KeySize512 ) {
throw new IllegalArgumentException("The key material must be 128, 192, 256, 384 or 512 bits of data");
}

_kid = kid;
_key = keyBytes;
_kid = kid;
_key = keyBytes;
_provider = provider;
}

Expand Down Expand Up @@ -148,7 +234,7 @@ public ListenableFuture<byte[]> decryptAsync(final byte[] ciphertext, final byte
ICryptoTransform transform = null;

try {
transform = algo.CreateDecryptor(_key, iv, authenticationData, _provider );
transform = algo.CreateDecryptor(_key, iv, authenticationData, authenticationTag, _provider );
} catch (Exception e) {
return Futures.immediateFailedFuture(e);
}
Expand All @@ -161,19 +247,6 @@ public ListenableFuture<byte[]> decryptAsync(final byte[] ciphertext, final byte
return Futures.immediateFailedFuture(e);
}

if (transform instanceof IAuthenticatedCryptoTransform) {

IAuthenticatedCryptoTransform authenticatedTransform = (IAuthenticatedCryptoTransform) transform;

if (authenticationData == null || authenticationTag == null) {
throw new IllegalArgumentException("AuthenticatingCryptoTransform requires authenticationData and authenticationTag");
}

if (!sequenceEqualConstantTime(authenticationTag, authenticatedTransform.getTag())) {
throw new IllegalArgumentException("Data is not authentic");
}
}

return Futures.immediateFuture(result);
}

Expand Down Expand Up @@ -313,24 +386,4 @@ public ListenableFuture<Boolean> verifyAsync(final byte[] digest, final byte[] s
@Override
public void close() throws IOException {
}

public static boolean sequenceEqualConstantTime(byte[] self, byte[] other) {
if (self == null) {
throw new IllegalArgumentException("self");
}

if (other == null) {
throw new IllegalArgumentException("other");
}

// Constant time comparison of two byte arrays
long difference = (self.length & 0xffffffffl) ^ (other.length & 0xffffffffl);

for (int i = 0; i < self.length && i < other.length; i++) {
difference |= (self[i] & 0xffffffffl) ^ (other[i] & 0xffffffffl);
}

return difference == 0;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, byte[] authentica
}

@Override
public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData, byte[] authenticationTag) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {

if (key == null || key.length < keySizeInBytes) {
throw new InvalidKeyException("key must be at least " + keySize + " bits in length");
Expand All @@ -107,7 +107,7 @@ public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authentica
}

@Override
public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData, byte[] authenticationTag, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {

if (key == null || key.length < keySizeInBytes) {
throw new InvalidKeyException("key must be at least " + keySize + " bits in length");
Expand Down
Loading

0 comments on commit 8909087

Please sign in to comment.