All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.sqlserver.jdbc.SQLServerSecurityUtility Maven / Gradle / Ivy

There is a newer version: 12.8.1.jre11
Show newest version
//---------------------------------------------------------------------------------------------------------------------------------
// File: SQLServerSecurityUtility.java
//
//
// Microsoft JDBC Driver for SQL Server
// Copyright(c) Microsoft Corporation
// All rights reserved.
// MIT License
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the ""Software""), 
//  to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//  and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 
//  IN THE SOFTWARE.
//---------------------------------------------------------------------------------------------------------------------------------
 
 
package com.microsoft.sqlserver.jdbc;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;


import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;


class SQLServerSecurityUtility {
	
    /**
     * Give the hash of given plain text
     * @param plainText 
     * @param key
     * @param length
     * @return hash of the plain text using provided key 
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
	static byte [] getHMACWithSHA256 (byte [] plainText,byte[] key, int length) throws NoSuchAlgorithmException, InvalidKeyException{
		byte [] computedHash;
		byte [] hash=new byte [length];
			Mac mac = Mac.getInstance("HmacSHA256");
			SecretKeySpec ivkeySpec = new SecretKeySpec(key, "HmacSHA256");
			mac.init(ivkeySpec);
			computedHash=mac.doFinal(plainText);
			// truncating hash if needed 
			System.arraycopy(computedHash, 0, hash, 0, hash.length);
		 return hash;
	}
	
	/**
	 * Compare two arrays
	 * @param buffer1 first array
	 * @param buffer2 second array 
	 * @param buffer2Index 
	 * @param lengthToCompare
	 * @return true if array contains same bytes otherwise false
	 */
	static boolean compareBytes(byte[] buffer1, byte[] buffer2, int buffer2Index, int lengthToCompare){
		 if (null == buffer1 || null == buffer2) {
             return false;
         }
		 
		 if ((buffer2.length -buffer2Index) < lengthToCompare) {
             return false;
         }
		 
		 for (int index = 0; index < buffer1.length && index < lengthToCompare; ++index) {
             if (buffer1[index] != buffer2[buffer2Index + index]) {
                 return false;
             }
         }
		 return true;
		
	}

	
    /*
     *  Encrypts the ciphertext.
     */
    static byte[] encryptWithKey(byte[] plainText, CryptoMetadata md, SQLServerConnection connection) throws SQLServerException 
    {
    	String serverName = connection.getTrustedServerNameAE();
        assert serverName != null : "Server name should npt be null in EncryptWithKey";

        // Initialize cipherAlgo if not already done.
        if (!md.IsAlgorithmInitialized()) {
            SQLServerSecurityUtility.decryptSymmetricKey(md, connection);
        }

        assert md.IsAlgorithmInitialized();
        byte[] cipherText = md.cipherAlgorithm.encryptData(plainText); // this call succeeds or throws.
        if (null == cipherText || 0 == cipherText.length) {
	         throw new SQLServerException(null, SQLServerException.getErrString("R_NullCipherTextAE"), null, 0, false);  
        }
        return cipherText;
    }
	
	/**
	 * Return the algorithm name mapped to an Id
	 * @param cipherAlgorithmId The cipher algorithm Id
	 * @param cipherAlgorithmName The cipher algorithm name 
	 * @return The cipher algorithm name
	 */
    private static String ValidateAndGetEncryptionAlgorithmName (byte cipherAlgorithmId, String cipherAlgorithmName) throws SQLServerException
    {
    	// Custom cipher algorithm not supported for CTP.
        if (TDS.AEAD_AES_256_CBC_HMAC_SHA256 != cipherAlgorithmId) {
	         throw new SQLServerException(null, SQLServerException.getErrString("R_CustomCipherAlgorithmNotSupportedAE"), null, 0, false);  
        }        
        return SQLServerAeadAes256CbcHmac256Algorithm.algorithmName;
	}

	/**
	 * Decrypts the symmetric key and saves it in metadata. In addition, initializes the 
	 * SqlClientEncryptionAlgorithm for rapid decryption.
	 * @param md The cipher metadata
	 * @param connection The connection
	 */
    static void decryptSymmetricKey(CryptoMetadata md, SQLServerConnection connection) throws SQLServerException
    {
        assert null != md : "md should not be null in DecryptSymmetricKey.";
        assert null != md.cekTableEntry : "md.EncryptionInfo should not be null in DecryptSymmetricKey.";
        assert null != md.cekTableEntry.columnEncryptionKeyValues : "md.EncryptionInfo.ColumnEncryptionKeyValues should not be null in DecryptSymmetricKey.";

        SQLServerSymmetricKey symKey = null;
        EncryptionKeyInfo encryptionkeyInfoChosen = null;
        SQLServerSymmetricKeyCache cache = SQLServerSymmetricKeyCache.getInstance();
        Iterator it = md.cekTableEntry.columnEncryptionKeyValues.iterator();
        SQLServerException lastException = null;
        while(it.hasNext())
        {
        	EncryptionKeyInfo keyInfo = it.next();
        	try{
        		symKey = cache.getKey(keyInfo, connection);
            	if (null != symKey) {
            		encryptionkeyInfoChosen = keyInfo;
            		break;
            	}
        	}
        	catch(SQLServerException e)
        	{
        		lastException = e;
        	}
        }

        if (null == symKey) {
        	if( null != lastException)
        	{
        		throw lastException;
        	}
        	else {
        		throw new SQLServerException(null, SQLServerException.getErrString("R_CEKDecryptionFailed"), null, 0, false);
        	}
        }

        // Given the symmetric key instantiate a SqlClientEncryptionAlgorithm object and cache it in metadata. 
        md.cipherAlgorithm = null;
        SQLServerEncryptionAlgorithm cipherAlgorithm = null;
        String algorithmName = ValidateAndGetEncryptionAlgorithmName(md.cipherAlgorithmId, md.cipherAlgorithmName); // may throw
        cipherAlgorithm = SQLServerEncryptionAlgorithmFactoryList.getInstance().getAlgorithm(symKey, md.encryptionType, algorithmName); // will validate algorithm name and type
        assert null != cipherAlgorithm : "Cipher algorithm cannot be null in DecryptSymmetricKey";
        md.cipherAlgorithm = cipherAlgorithm;
        md.encryptionKeyInfo = encryptionkeyInfoChosen;
        return;
    }	
	
    /*
     *  Decrypts the ciphertext.
     */
    static byte[] decryptWithKey(byte[] cipherText, CryptoMetadata md, SQLServerConnection connection) throws SQLServerException 
    {
    	String serverName = connection.getTrustedServerNameAE();
        assert null != serverName : "serverName should not be null in DecryptWithKey.";

        // Initialize cipherAlgo if not already done.
        if (!md.IsAlgorithmInitialized()) { 
            SQLServerSecurityUtility.decryptSymmetricKey(md, connection);
        }

        assert md.IsAlgorithmInitialized() : "Decryption Algorithm is not initialized";
        byte[] plainText = md.cipherAlgorithm.decryptData(cipherText); // this call succeeds or throws.
        if (null == plainText) {
        	throw new SQLServerException(null, SQLServerException.getErrString("R_PlainTextNullAE"), null, 0, false);  
        }

        return plainText;
    }	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy