Skip to content

Commit

Permalink
11.2.2 backport 1948 1968 Added locks to encrypt/decrypt in truststor…
Browse files Browse the repository at this point in the history
…e password obfuscation and fixed race condition (#2000)
  • Loading branch information
tkyc authored Dec 14, 2022
1 parent fa48f7c commit 1b43d24
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 22 deletions.
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ if(hasProperty('buildProfile') && buildProfile == "jre8") {
}
}

jar.archiveFileName = "${archivesBaseName}-${version}.${jreVersion}-preview.jar"
jar.archiveFileName = "${archivesBaseName}-${version}.${jreVersion}.jar"
jar {
manifest {
attributes 'Title': "Microsoft JDBC Driver ${archiveVersion} for SQL Server",
Expand Down Expand Up @@ -130,7 +130,7 @@ dependencies {
implementation 'org.osgi:org.osgi.core:6.0.0',
'org.osgi:org.osgi.compendium:5.0.0'
compileOnly 'com.azure:azure-security-keyvault-keys:4.2.8',
'com.azure:azure-identity:1.3.3',
'com.azure:azure-identity:1.7.0-beta.2',
'org.antlr:antlr4-runtime:4.9.2',
'com.google.code.gson:gson:2.8.7',
'org.bouncycastle:bcprov-jdk15on:1.69',
Expand All @@ -152,7 +152,7 @@ dependencies {
'com.google.code.gson:gson:2.8.7',
'org.bouncycastle:bcprov-jdk15on:1.69',
'com.azure:azure-security-keyvault-keys:4.2.8',
'com.azure:azure-identity:1.3.3',
'com.azure:azure-identity:1.7.0-beta.2',
'com.microsoft.azure:adal4j:1.6.7',
'com.h2database:h2:1.4.200'
}
58 changes: 39 additions & 19 deletions src/main/java/com/microsoft/sqlserver/jdbc/SecureStringUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.security.SecureRandom;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
Expand Down Expand Up @@ -41,7 +43,11 @@ final class SecureStringUtil {
private Cipher decryptCipher;

/* singleton instance */
private static SecureStringUtil instance;
private static volatile SecureStringUtil instance;

private static final Lock INSTANCE_LOCK = new ReentrantLock();
private static final Lock ENCRYPT_LOCK = new ReentrantLock();
private static final Lock DECRYPT_LOCK = new ReentrantLock();

/**
* Get reference to SecureStringUtil instance
Expand All @@ -53,7 +59,14 @@ final class SecureStringUtil {
*/
static SecureStringUtil getInstance() throws SQLServerException {
if (instance == null) {
instance = new SecureStringUtil();
INSTANCE_LOCK.lock();
try {
if (instance == null) {
instance = new SecureStringUtil();
}
} finally {
INSTANCE_LOCK.unlock();
}
}
return instance;
}
Expand Down Expand Up @@ -90,18 +103,19 @@ private SecureStringUtil() throws SQLServerException {
* @return encrypted string
*
* @throws SQLServerException
* if error
* Throws an exception if the method fails to encrypt the character array
*/
byte[] getEncryptedBytes(char[] chars) throws SQLServerException {
if (chars == null)
return null;

byte[] iv = new byte[IV_LENGTH];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
GCMParameterSpec ivParamSpec = new GCMParameterSpec(TAG_LENGTH * 8, iv);

ENCRYPT_LOCK.lock();
try {
if (chars == null) {
return null;
}

byte[] iv = new byte[IV_LENGTH];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
GCMParameterSpec ivParamSpec = new GCMParameterSpec(TAG_LENGTH * 8, iv);
encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParamSpec);

byte[] cipherText = encryptCipher.doFinal(Util.charsToBytes(chars));
Expand All @@ -113,29 +127,34 @@ byte[] getEncryptedBytes(char[] chars) throws SQLServerException {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_EncryptionFailed"));
Object[] msgArgs = {e.getMessage()};
throw new SQLServerException(this, form.format(msgArgs), null, 0, false);
} finally {
ENCRYPT_LOCK.unlock();
}
}

/**
* Get decrypted value of an encrypted string
*
* @param bytes
* The byte array to decrypt into a character array
*
* @return decrypted string
*
* @throws SQLServerException
* Throws an exception if the method fails to decrypt the byte array
*/
char[] getDecryptedChars(byte[] bytes) throws SQLServerException {
if (bytes == null)
return null;

byte[] iv = new byte[IV_LENGTH];
System.arraycopy(bytes, 0, iv, 0, IV_LENGTH);

GCMParameterSpec ivParamSpec = new GCMParameterSpec(TAG_LENGTH * 8, iv);

DECRYPT_LOCK.lock();
byte[] plainText = null;
try {
if (bytes == null) {
return null;
}

byte[] iv = new byte[IV_LENGTH];
System.arraycopy(bytes, 0, iv, 0, IV_LENGTH);

GCMParameterSpec ivParamSpec = new GCMParameterSpec(TAG_LENGTH * 8, iv);
decryptCipher.init(Cipher.DECRYPT_MODE, secretKey, ivParamSpec);

plainText = decryptCipher.doFinal(bytes, IV_LENGTH, bytes.length - IV_LENGTH);
Expand All @@ -148,6 +167,7 @@ char[] getDecryptedChars(byte[] bytes) throws SQLServerException {
if (plainText != null) {
Arrays.fill(plainText, (byte) 0);
}
DECRYPT_LOCK.unlock();
}
}
}

0 comments on commit 1b43d24

Please sign in to comment.