diff --git a/src/share/classes/com/sun/crypto/provider/AESCrypt.java b/src/share/classes/com/sun/crypto/provider/AESCrypt.java index c85f715e96714d6262c39af5dec8f2712486b7fc..0adb07092e5f6482cb4d4aacda5d4ecb58652038 100644 --- a/src/share/classes/com/sun/crypto/provider/AESCrypt.java +++ b/src/share/classes/com/sun/crypto/provider/AESCrypt.java @@ -38,6 +38,7 @@ package com.sun.crypto.provider; import java.security.InvalidKeyException; import java.security.MessageDigest; +import java.util.Objects; /** * Rijndael --pronounced Reindaal-- is a symmetric cipher with a 128-bit @@ -346,7 +347,15 @@ final class AESCrypt extends SymmetricCipher implements AESConstants * Encrypt exactly one block of plaintext. */ void encryptBlock(byte[] in, int inOffset, - byte[] out, int outOffset) + byte[] out, int outOffset) { + cryptBlockCheck(in, inOffset); + cryptBlockCheck(out, outOffset); + implEncryptBlock(in, inOffset, out, outOffset); + } + + // Encryption operation. Possibly replaced with a compiler intrinsic. + private void implEncryptBlock(byte[] in, int inOffset, + byte[] out, int outOffset) { int keyOffset = 0; int t0 = ((in[inOffset++] ) << 24 | @@ -412,12 +421,19 @@ final class AESCrypt extends SymmetricCipher implements AESConstants out[outOffset ] = (byte)(S[(t2 ) & 0xFF] ^ (tt )); } - /** * Decrypt exactly one block of plaintext. */ void decryptBlock(byte[] in, int inOffset, - byte[] out, int outOffset) + byte[] out, int outOffset) { + cryptBlockCheck(in, inOffset); + cryptBlockCheck(out, outOffset); + implDecryptBlock(in, inOffset, out, outOffset); + } + + // Decrypt operation. Possibly replaced with a compiler intrinsic. + private void implDecryptBlock(byte[] in, int inOffset, + byte[] out, int outOffset) { int keyOffset = 4; int t0 = ((in[inOffset++] ) << 24 | @@ -572,6 +588,25 @@ final class AESCrypt extends SymmetricCipher implements AESConstants out[outOffset ] = (byte)(Si[(a0 ) & 0xFF] ^ (t1 )); } + // Used to perform all checks required by the Java semantics + // (i.e., null checks and bounds checks) on the input parameters + // to encryptBlock and to decryptBlock. + // Normally, the Java Runtime performs these checks, however, as + // encryptBlock and decryptBlock are possibly replaced with + // compiler intrinsics, the JDK performs the required checks instead. + // Does not check accesses to class-internal (private) arrays. + private static void cryptBlockCheck(byte[] array, int offset) { + Objects.requireNonNull(array); + + if (offset < 0 || offset >= array.length) { + throw new ArrayIndexOutOfBoundsException(offset); + } + + int largestIndex = offset + AES_BLOCK_SIZE - 1; + if (largestIndex < 0 || largestIndex >= array.length) { + throw new ArrayIndexOutOfBoundsException(largestIndex); + } + } /** * Expand a user-supplied key material into a session key. diff --git a/src/share/classes/com/sun/crypto/provider/CipherBlockChaining.java b/src/share/classes/com/sun/crypto/provider/CipherBlockChaining.java index 1d33117dd5d89b015d8775c1426850a9c67c07bb..0f8040fe20cf0ad74bdc7631a14eec15904260fc 100644 --- a/src/share/classes/com/sun/crypto/provider/CipherBlockChaining.java +++ b/src/share/classes/com/sun/crypto/provider/CipherBlockChaining.java @@ -27,6 +27,7 @@ package com.sun.crypto.provider; import java.security.InvalidKeyException; import java.security.ProviderException; +import java.util.Objects; /** @@ -138,18 +139,24 @@ class CipherBlockChaining extends FeedbackCipher { * @return the length of the encrypted data */ int encrypt(byte[] plain, int plainOffset, int plainLen, - byte[] cipher, int cipherOffset) - { + byte[] cipher, int cipherOffset) { if (plainLen <= 0) { return plainLen; } - if ((plainLen % blockSize) != 0) { - throw new ProviderException("Internal error in input buffering"); - } + cryptBlockSizeCheck(plainLen); + cryptNullAndBoundsCheck(plain, plainOffset, plainLen); + cryptNullAndBoundsCheck(cipher, cipherOffset, plainLen); + return implEncrypt(plain, plainOffset, plainLen, + cipher, cipherOffset); + } + + private int implEncrypt(byte[] plain, int plainOffset, int plainLen, + byte[] cipher, int cipherOffset) + { int endIndex = plainOffset + plainLen; for (; plainOffset < endIndex; - plainOffset+=blockSize, cipherOffset += blockSize) { + plainOffset += blockSize, cipherOffset += blockSize) { for (int i = 0; i < blockSize; i++) { k[i] = (byte)(plain[i + plainOffset] ^ r[i]); } @@ -182,14 +189,19 @@ class CipherBlockChaining extends FeedbackCipher { * @return the length of the decrypted data */ int decrypt(byte[] cipher, int cipherOffset, int cipherLen, - byte[] plain, int plainOffset) - { + byte[] plain, int plainOffset) { if (cipherLen <= 0) { return cipherLen; } - if ((cipherLen % blockSize) != 0) { - throw new ProviderException("Internal error in input buffering"); - } + cryptBlockSizeCheck(cipherLen); + cryptNullAndBoundsCheck(cipher, cipherOffset, cipherLen); + cryptNullAndBoundsCheck(plain, plainOffset, cipherLen); + return implDecrypt(cipher, cipherOffset, cipherLen, plain, plainOffset); + } + + private int implDecrypt(byte[] cipher, int cipherOffset, int cipherLen, + byte[] plain, int plainOffset) + { int endIndex = cipherOffset + cipherLen; for (; cipherOffset < endIndex; @@ -202,4 +214,23 @@ class CipherBlockChaining extends FeedbackCipher { } return cipherLen; } + + private void cryptBlockSizeCheck(int len) { + if ((len % blockSize) != 0) { + throw new ProviderException("Internal error in input buffering"); + } + } + + private static void cryptNullAndBoundsCheck(byte[] array, int offset, int len) { + Objects.requireNonNull(array); + + if (offset < 0 || offset >= array.length) { + throw new ArrayIndexOutOfBoundsException(offset); + } + + int endIndex = offset + len - 1; + if (endIndex < 0 || endIndex >= array.length) { + throw new ArrayIndexOutOfBoundsException(endIndex); + } + } } diff --git a/src/share/classes/sun/security/provider/DigestBase.java b/src/share/classes/sun/security/provider/DigestBase.java index c3ac4ac36f59ac016d3071557cf7f0de05719343..89b1d77f31bf5dab9d876b5b6b99500f1c4e6459 100644 --- a/src/share/classes/sun/security/provider/DigestBase.java +++ b/src/share/classes/sun/security/provider/DigestBase.java @@ -29,6 +29,7 @@ import java.security.MessageDigestSpi; import java.security.DigestException; import java.security.ProviderException; import java.util.Arrays; +import java.util.Objects; /** * Common base message digest implementation for the Sun provider. @@ -137,12 +138,35 @@ abstract class DigestBase extends MessageDigestSpi implements Cloneable { // compress complete blocks private int implCompressMultiBlock(byte[] b, int ofs, int limit) { + implCompressMultiBlockCheck(b, ofs, limit); + return implCompressMultiBlock0(b, ofs, limit); + } + + private int implCompressMultiBlock0(byte[] b, int ofs, int limit) { for (; ofs <= limit; ofs += blockSize) { implCompress(b, ofs); } return ofs; } + private void implCompressMultiBlockCheck(byte[] b, int ofs, int limit) { + if (limit < 0) { + return; // not an error because implCompressMultiBlockImpl won't execute if limit < 0 + // and an exception is thrown if ofs < 0. + } + + Objects.requireNonNull(b); + + if (ofs < 0 || ofs >= b.length) { + throw new ArrayIndexOutOfBoundsException(ofs); + } + + int endIndex = (limit / blockSize) * blockSize + blockSize - 1; + if (endIndex >= b.length) { + throw new ArrayIndexOutOfBoundsException(endIndex); + } + } + // reset this object. See JCA doc. protected final void engineReset() { if (bytesProcessed == 0) { diff --git a/src/share/classes/sun/security/provider/SHA.java b/src/share/classes/sun/security/provider/SHA.java index 24dc0b2897f60ef79cd4bd9ecc3aa142a0b450fc..dfa477adf2d7afd8af6829f84672eebe5996e268 100644 --- a/src/share/classes/sun/security/provider/SHA.java +++ b/src/share/classes/sun/security/provider/SHA.java @@ -27,6 +27,8 @@ package sun.security.provider; import java.util.Arrays; +import java.util.Objects; + import static sun.security.provider.ByteArrayAccess.*; /** @@ -123,8 +125,26 @@ public final class SHA extends DigestBase { * "old" NIST Secure Hash Algorithm. */ void implCompress(byte[] buf, int ofs) { + implCompressCheck(buf, ofs); + implCompress0(buf, ofs); + } + + private void implCompressCheck(byte[] buf, int ofs) { + Objects.requireNonNull(buf); + + // The checks performed by the method 'b2iBig64' + // are sufficient for the case when the method + // 'implCompressImpl' is replaced with a compiler + // intrinsic. b2iBig64(buf, ofs, W); + } + // The method 'implCompressImpl seems not to use its parameters. + // The method can, however, be replaced with a compiler intrinsic + // that operates directly on the array 'buf' (starting from + // offset 'ofs') and not on array 'W', therefore 'buf' and 'ofs' + // must be passed as parameter to the method. + private void implCompress0(byte[] buf, int ofs) { // The first 16 ints have the byte stream, compute the rest of // the buffer for (int t = 16; t <= 79; t++) { diff --git a/src/share/classes/sun/security/provider/SHA2.java b/src/share/classes/sun/security/provider/SHA2.java index 6f34c8d55dfc09b0dab5fc0e58afa1a8c9e40d8e..25f13d0736477f42dfbeba755e3e902f30d91af4 100644 --- a/src/share/classes/sun/security/provider/SHA2.java +++ b/src/share/classes/sun/security/provider/SHA2.java @@ -27,6 +27,8 @@ package sun.security.provider; import java.util.Arrays; +import java.util.Objects; + import static sun.security.provider.ByteArrayAccess.*; /** @@ -193,8 +195,26 @@ abstract class SHA2 extends DigestBase { * Process the current block to update the state variable state. */ void implCompress(byte[] buf, int ofs) { + implCompressCheck(buf, ofs); + implCompress0(buf, ofs); + } + + private void implCompressCheck(byte[] buf, int ofs) { + Objects.requireNonNull(buf); + + // The checks performed by the method 'b2iBig64' + // are sufficient for the case when the method + // 'implCompressImpl' is replaced with a compiler + // intrinsic. b2iBig64(buf, ofs, W); + } + // The method 'implCompressImpl' seems not to use its parameters. + // The method can, however, be replaced with a compiler intrinsic + // that operates directly on the array 'buf' (starting from + // offset 'ofs') and not on array 'W', therefore 'buf' and 'ofs' + // must be passed as parameter to the method. + private void implCompress0(byte[] buf, int ofs) { // The first 16 ints are from the byte stream, compute the rest of // the W[]'s for (int t = 16; t < ITERATION; t++) { diff --git a/src/share/classes/sun/security/provider/SHA5.java b/src/share/classes/sun/security/provider/SHA5.java index 90c12526d8e34fa61fe51125303cef043a56030e..ceba1fc2b2dd6b1b0c1ae8a71745b8c2cd4e0dc2 100644 --- a/src/share/classes/sun/security/provider/SHA5.java +++ b/src/share/classes/sun/security/provider/SHA5.java @@ -26,6 +26,7 @@ package sun.security.provider; import java.util.Arrays; +import java.util.Objects; import static sun.security.provider.ByteArrayAccess.*; @@ -209,8 +210,26 @@ abstract class SHA5 extends DigestBase { * "old" NIST Secure Hash Algorithm. */ final void implCompress(byte[] buf, int ofs) { + implCompressCheck(buf, ofs); + implCompress0(buf, ofs); + } + + private void implCompressCheck(byte[] buf, int ofs) { + Objects.requireNonNull(buf); + + // The checks performed by the method 'b2iBig128' + // are sufficient for the case when the method + // 'implCompressImpl' is replaced with a compiler + // intrinsic. b2lBig128(buf, ofs, W); + } + // The method 'implCompressImpl' seems not to use its parameters. + // The method can, however, be replaced with a compiler intrinsic + // that operates directly on the array 'buf' (starting from + // offset 'ofs') and not on array 'W', therefore 'buf' and 'ofs' + // must be passed as parameter to the method. + private final void implCompress0(byte[] buf, int ofs) { // The first 16 longs are from the byte stream, compute the rest of // the W[]'s for (int t = 16; t < ITERATION; t++) {