Google Gives Free Security Keys to Activists, But Not if You’re in Iran or Syria

Sources and a document show how Google bars nonprofits from telling activists in certain countries about their products. Continue reading Google Gives Free Security Keys to Activists, But Not if You’re in Iran or Syria

Features Added to Azure for GDPR

secure password

Microsoft has added a number of new features to Azure to support the European Union’s General Data Protection Regulation (GDPR), which many organizations outside and inside of Europe will require to avoid stiff penalties.

The post Features Added to Azure for GDPR appeared first on Petri.

Continue reading Features Added to Azure for GDPR

How can an attacker downgrade/modify the cipher suites when they are MACed? (Freak, Logjam use downgrade attacks)

In the Finished handshake of TLS all previous messages exchanged are sent from the client to the server (and reverse) and protected by a MAC. This is what also “prevents” TLS_FALLBACK_SCSV from being modified/deleted by an at… Continue reading How can an attacker downgrade/modify the cipher suites when they are MACed? (Freak, Logjam use downgrade attacks)

Why does Java allow AES-256 bit encryption on systems without JCE unlimited strength policies if using PBE?

It’s fairly standard knowledge that due to the cryptography export controls, Oracle JRE ships with “limited” cryptographic strength enabled as listed in the JCA Documentation. For AES, the default max happens to be 128 bit key length. To enable 192 bit or 256 bit encryption, the JCE Unlimited Strength Jurisdiction Policy files must be installed into the JRE.

I came across a situation by accident recently that lead me to believe there is an issue with this enforcement. I’m not sure I would call it a bug, but it’s definitely not well documented (or at least I can’t find anything documenting it).

The key length check is done inside cipher.init(), and I believe it uses Cipher.getMaxAllowedKeyLength("AES") to determine if the max key size is 128 or Integer.MAX_VALUE.

Using normal keyed encryption, this check is fine. On a default JRE installation, the code below executes as expected (I’m using Groovy for the test but I’ve tried this in pure Java as well):

static boolean isUnlimitedStrengthCrypto() {
    Cipher.getMaxAllowedKeyLength("AES") > 128
}

@Test
public void testShouldEncryptAndDecryptWith128BitKey() throws Exception {
    // Arrange
    MessageDigest sha1 = MessageDigest.getInstance("SHA1")
    String key = Hex.encodeHexString(sha1.digest("thisIsABadPassword".getBytes()))[0..<32]
    String iv = Hex.encodeHexString(sha1.digest("thisIsABadIv".getBytes()))[0..<32]

    logger.info("Key: ${key}")
    logger.info("IV : ${iv}")

    SecretKey secretKey = new SecretKeySpec(Hex.decodeHex(key.toCharArray()), "AES")
    IvParameterSpec ivParameterSpec = new IvParameterSpec(Hex.decodeHex(iv.toCharArray()))

    // Act    
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec)

    String message = "This is a plaintext message."

    byte[] cipherBytes = cipher.doFinal(message.getBytes())

    cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec)

    byte[] recoveredBytes = cipher.doFinal(cipherBytes)

    String recovered = new String(recoveredBytes)
    System.out.println("Recovered message: " + recovered)

    // Assert
    assert recovered == message
}

This generates the output:

[main] INFO  *.crypto.OpenSSLPBEEncryptorTest  - Key: 6d71f677ecb99cf623246fb48a1d8130
[main] INFO  *.crypto.OpenSSLPBEEncryptorTest  - IV : 912ed675905eb4cb0f9f5714c9c9ec39

And this test:

@Test
public void testShouldNotEncryptAndDecryptWith256BitKey() throws Exception {
    // Arrange
    Assume.assumeTrue("This test should only run when unlimited (256 bit) encryption is not available", !isUnlimitedStrengthCrypto())

    MessageDigest sha1 = MessageDigest.getInstance("SHA1")
    String key = Hex.encodeHexString(sha1.digest("thisIsABadPassword".getBytes()))[0..<32] * 2
    String iv = Hex.encodeHexString(sha1.digest("thisIsABadIv".getBytes()))[0..<32]

    logger.info("Key: ${key}")
    logger.info("IV : ${iv}")

    SecretKey secretKey = new SecretKeySpec(Hex.decodeHex(key.toCharArray()), "AES")
    IvParameterSpec ivParameterSpec = new IvParameterSpec(Hex.decodeHex(iv.toCharArray()))

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")

    // Act
    def msg = shouldFail(InvalidKeyException) {
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec)
    }

    // Assert
    assert msg =~ "Illegal key size"
}

Generates this output:

[main] INFO  *.crypto.OpenSSLPBEEncryptorTest  - Key: 6d71f677ecb99cf623246fb48a1d81306d71f677ecb99cf623246fb48a1d8130
[main] INFO  *.crypto.OpenSSLPBEEncryptorTest  - IV : 912ed675905eb4cb0f9f5714c9c9ec39

And successfully passes by throwing the exception.

The problem arises when password-based encryption is used.

Because the key derivation from the password (and salt, if provided), occurs during cipher.init() but after the key length check, the length check actually applies to the byte[] representation of SecretKey.getEncoded(). This means that if a password <= 16 characters (16 bytes / 128 bits) is used, the check will pass even if the cipher specified uses a 256 bit key. The derived key will be 256 bits even though the jurisdiction policy prohibits this. Conversely, if a password > 16 characters is used, even with a 128 bit cipher, the length check will fail and an InvalidKeyException will be thrown. The following code demonstrates this:

@Test
public void testShouldEncryptAndDecryptWithPBEShortPassword() throws Exception {
    // Arrange
    final String PASSWORD = "password"
    String salt = "saltsalt"

    logger.info("Password: ${PASSWORD}")
    logger.info("Salt    : ${salt}")

    String algorithm;
    algorithm = "PBEWITHMD5AND256BITAES-CBC-OPENSSL"
    PBEKeySpec pbeSpec = new PBEKeySpec(PASSWORD.toCharArray());
    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(algorithm, "BC");
    SecretKey secretKey = secretKeyFactory.generateSecret(pbeSpec);
    PBEParameterSpec saltParams = new PBEParameterSpec(salt.getBytes("US-ASCII"), 0);

    // Act
    Cipher cipher = Cipher.getInstance(algorithm, "BC");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, saltParams);

    String message = "This is a plaintext message."

    byte[] cipherBytes = cipher.doFinal(message.getBytes())

    cipher.init(Cipher.DECRYPT_MODE, secretKey, saltParams)

    byte[] recoveredBytes = cipher.doFinal(cipherBytes)

    String recovered = new String(recoveredBytes)
    System.out.println("Recovered message: " + recovered)

    // Assert
    assert recovered == message
}

@Test
public void testShouldNotEncryptAndDecryptWithPBELongPassword() throws Exception {
    // Arrange
    Assume.assumeTrue("This test should only run when unlimited (256 bit) encryption is not available", !isUnlimitedStrengthCrypto())

    final String PASSWORD = "thisIsABadPassword"
    String salt = "saltsalt"

    logger.info("Password: ${PASSWORD}")
    logger.info("Salt    : ${salt}")

    String algorithm;
    algorithm = "PBEWITHMD5AND256BITAES-CBC-OPENSSL"
    PBEKeySpec pbeSpec = new PBEKeySpec(PASSWORD.toCharArray());
    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(algorithm, "BC");
    SecretKey secretKey = secretKeyFactory.generateSecret(pbeSpec);
    PBEParameterSpec saltParams = new PBEParameterSpec(salt.getBytes("US-ASCII"), 0);

    Cipher cipher = Cipher.getInstance(algorithm, "BC");

    // Act
    def msg = shouldFail(InvalidKeyException) {
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, saltParams);
    }

    // Assert
    assert msg =~ "Illegal key size"
}

Both tests “pass” in that on a system with “limited” strength cryptography, 256 bit encryption is still available if the password is short enough. Conversely, this test demonstrates that a long password causes an exception even when using 128 bit encryption:

@Test
public void testShouldNotEncryptAndDecryptWithPBELongPasswordEvenWith128BitKey() throws Exception {
    // Arrange
    Assume.assumeTrue("This test should only run when unlimited (256 bit) encryption is not available", !isUnlimitedStrengthCrypto())

    final String PASSWORD = "thisIsABadPassword"
    String salt = "saltsalt"

    logger.info("Password: ${PASSWORD}")
    logger.info("Salt    : ${salt}")

    String algorithm;
    algorithm = "PBEWITHMD5AND128BITAES-CBC-OPENSSL"
    PBEKeySpec pbeSpec = new PBEKeySpec(PASSWORD.toCharArray());
    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(algorithm, "BC");
    SecretKey secretKey = secretKeyFactory.generateSecret(pbeSpec);
    PBEParameterSpec saltParams = new PBEParameterSpec(salt.getBytes("US-ASCII"), 0);

    Cipher cipher = Cipher.getInstance(algorithm, "BC");

    // Act
    def msg = shouldFail(InvalidKeyException) {
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, saltParams);
    }

    // Assert
    assert msg =~ "Illegal key size"
}

I thought it might be a false positive, so I used OpenSSL to encrypt files using 128 and 256 bit encryption with “long” and “short” passwords and tried to decrypt them with Java. The results are from a system with “limited” strength crypto:

$ openssl enc -aes-128-cbc -e -in plain.txt -out salted_raw_128_long.enc -k thisIsABadPassword -p
$ openssl enc -aes-128-cbc -e -in plain.txt -out salted_raw_128_short.enc -k password -p
$ openssl enc -aes-256-cbc -e -in plain.txt -out salted_raw_256_long.enc -k thisIsABadPassword -p
$ openssl enc -aes-256-cbc -e -in plain.txt -out salted_raw_256_short.enc -k password -p


Cipher  | Password length | Should Work | Does Work
--------|-----------------|-------------|-----------
AES-128 |   <= 16 chars   |     YES     |    YES
AES-128 |    > 16 chars   |     YES     |     NO
AES-256 |   <= 16 chars   |      NO     |    YES
AES-256 |    > 16 chars   |      NO     |     NO

I have a few questions:

  1. Can anyone else reproduce this behavior?
  2. Is this intended behavior or a bug?
  3. If intended, is it sufficiently documented somewhere?

Update After further research on a machine without the unlimited strength jurisdiction policies installed, I have determined these maximum password lengths for the following PBE algorithms:

Algorithm        |        Max Password Length
---------------------------------------------
PBEWITHMD5AND128BITAES-CBC-OPENSSL |    16
PBEWITHMD5AND192BITAES-CBC-OPENSSL |    16
PBEWITHMD5AND256BITAES-CBC-OPENSSL |    16
PBEWITHMD5ANDDES                   |    16
PBEWITHMD5ANDRC2                   |    16
PBEWITHSHA1ANDRC2                  |    16
PBEWITHSHA1ANDDES                  |    16
PBEWITHSHAAND128BITAES-CBC-BC      |     7
PBEWITHSHAAND192BITAES-CBC-BC      |     7
PBEWITHSHAAND256BITAES-CBC-BC      |     7
PBEWITHSHAAND40BITRC2-CBC          |     7
PBEWITHSHAAND128BITRC2-CBC         |     7
PBEWITHSHAAND40BITRC4              |     7
PBEWITHSHAAND128BITRC4             |     7
PBEWITHSHA256AND128BITAES-CBC-BC   |     7
PBEWITHSHA256AND192BITAES-CBC-BC   |     7
PBEWITHSHA256AND256BITAES-CBC-BC   |     7
PBEWITHSHAAND2-KEYTRIPLEDES-CBC    |     7
PBEWITHSHAAND3-KEYTRIPLEDES-CBC    |     7
PBEWITHSHAANDTWOFISH-CBC           |     7

Continue reading Why does Java allow AES-256 bit encryption on systems without JCE unlimited strength policies if using PBE?