import certificate and generate CMK and CEK using tsql, no long depends on SSMS

This commit is contained in:
v-kaywon 2017-07-24 13:33:52 -07:00 committed by Jenny Tam
parent 5240a3420a
commit 0fe5172651
7 changed files with 76 additions and 184 deletions

Binary file not shown.

View file

@ -0,0 +1,38 @@
USE $(dbname)
GO
/* DROP Column Encryption Key first, Column Master Key cannot be dropped until no encryption depends on it */
IF EXISTS (SELECT * FROM sys.column_encryption_keys WHERE [name] LIKE '%AEColumnKey%')
BEGIN
DROP COLUMN ENCRYPTION KEY [AEColumnKey]
END
GO
/* Can finally drop Column Master Key after the Encryption Key is dropped */
IF EXISTS (SELECT * FROM sys.column_master_keys WHERE [name] LIKE '%AEMasterKey%')
BEGIN
DROP COLUMN MASTER KEY [AEMasterKey]
END
GO
/* Recreate the Column Master Key */
CREATE COLUMN MASTER KEY [AEMasterKey]
WITH
(
KEY_STORE_PROVIDER_NAME = N'MSSQL_CERTIFICATE_STORE',
KEY_PATH = N'CurrentUser/my/237F94738E7F5214D8588006C2269DBC6B370816'
)
GO
/* Create Column Encryption Key using the Column Master Key */
/* ENCRYPTED_VALUE is generated by SSMS and it is always the same if the same Certificate is imported */
CREATE COLUMN ENCRYPTION KEY [AEColumnKey]
WITH VALUES
(
COLUMN_MASTER_KEY = [AEMasterKey],
ALGORITHM = 'RSA_OAEP',
ENCRYPTED_VALUE = 0x016E000001630075007200720065006E00740075007300650072002F006D0079002F00320033003700660039003400370033003800650037006600350032003100340064003800350038003800300030003600630032003200360039006400620063003600620033003700300038003100360039DE2397A08F6313E7820D75382D8469BE1C8F3CD47E3240A5A6D6F82D322F6EB1B103C9C47999A69FFB164D37E7891F60FFDB04ADEADEB990BE88AE488CAFB8774442DF909D2EF8BB5961A5C11B85BA7903E0E453B27B49CE0A30D14FF4F412B5737850A4C564B44C744E690E78FAECF007F9005E3E0FB4F8D6C13B016A6393B84BB3F83FEED397C4E003FF8C5BBDDC1F6156349A8B40EDC26398C9A03920DD81B9197BC83A7378F79ECB430A04B4CFDF3878B0219BB629F5B5BF3C2359A7498AD9A6F5D63EF15E060CDB10A65E6BF059C7A32237F0D9E00C8AC632CCDD68230774477D4F2E411A0E4D9B351E8BAA87793E64456370D91D4420B5FD9A252F6D9178AE3DD02E1ED57B7F7008114272419F505CBCEB109715A6C4331DEEB73653990A7140D7F83089B445C59E4858809D139658DC8B2781CB27A749F1CE349DC43238E1FBEAE0155BF2DBFEF6AFD9FD2BD1D14CEF9AC125523FD1120488F24416679A6041184A2719B0FC32B6C393FF64D353A3FA9BC4FA23DFDD999B0771A547B561D72B92A0B2BB8B266BC25191F2A0E2F8D93648F8750308DCD79BE55A2F8D5FBE9285265BEA66173CD5F5F21C22CC933AE2147F46D22BFF329F6A712B3D19A6488DDEB6FDAA5B136B29ADB0BA6B6D1FD6FBA5D6A14F76491CB000FEE4769D5B268A3BF50EA3FBA713040944558EDE99D38A5828E07B05236A4475DA27915E
)
GO

View file

@ -1,37 +0,0 @@
Param(
[Parameter(Mandatory=$True,Position=1)]
[string]$serverName,
[Parameter(Mandatory=$True,Position=2)]
[string]$databaseName,
[Parameter(Mandatory=$True,Position=3)]
[string]$userName,
[Parameter(Mandatory=$True,Position=4)]
[string]$password)
# Create a column master key in Windows Certificate Store.
$cert1 = New-SelfSignedCertificate -Subject "PHPAlwaysEncryptedCert" -CertStoreLocation Cert:CurrentUser\My -KeyExportPolicy Exportable -Type DocumentEncryptionCert -KeyUsage DataEncipherment -KeySpec KeyExchange
# Import the SqlServer module.
Import-Module "SqlServer"
#For SQL Server Authentication
Add-Type -AssemblyName "Microsoft.SqlServer.Smo"
$MySQL = new-object('Microsoft.SqlServer.Management.Smo.Server') $serverName
$MySQL.ConnectionContext.LoginSecure = $false
$MySQL.ConnectionContext.set_Login($userName)
$MySQL.ConnectionContext.set_Password($password)
$database = $MySQL.Databases[$databaseName]
# Create a SqlColumnMasterKeySettings object for your column master key.
$cmkSettings = New-SqlCertificateStoreColumnMasterKeySettings -CertificateStoreLocation "CurrentUser" -Thumbprint $cert1.Thumbprint
# Create column master key metadata in the database.
$cmkName = "CMK1"
New-SqlColumnMasterKey -Name $cmkName -InputObject $database -ColumnMasterKeySettings $cmkSettings
# Generate a column encryption key, encrypt it with the column master key and create column encryption key metadata in the database.
$cekName = "CEK1"
New-SqlColumnEncryptionKey -Name $cekName -InputObject $database -ColumnMasterKey $cmkName
# Disconnect
$MySQL.ConnectionContext.Disconnect()

View file

@ -68,10 +68,13 @@ def is_ae_qualified( server, uid, pwd ):
def setupAE( server, dbname, uid, pwd):
if platform.system() == 'Windows':
# import self signed certificate
dir_name = os.path.realpath(__file__)
cert_name = os.path.join(dir_name, "certificate.ps1")
inst_command = 'powershell -executionPolicy Unrestricted -file ' + cert_name + ' ' + server + ' ' + dbname + ' ' + uid + ' ' + pwd
executeCommmand(inst_command)
cert_name = os.path.join(dir_name, "PHPcert.ps1")
inst_command = "certutil -user -p '' -importPFX My " + cert_name + " NoRoot"
executeCommand(inst_command)
# create Column Master Key and Column Encryption Key
executeSQLscript('ae_keys.sql', conn_options, dbname)
if __name__ == '__main__':
parser = argparse.ArgumentParser()

View file

@ -1,84 +0,0 @@
<?php
// exact numerics
$bigint_params = array(2147483648, -922337203685477580, 922337203685477580, -2147583649, 461168601735364608, -461168601735364608);
$int_params = array(32768, -2147483647, 2147483647, -32769, 1073725440, -1073725440);
$smallint_params = array(256, -32767, 32767, -1, 16256, -16256);
$tinyint_params = array(128, 0, 255, 96, 64, 162);
$decimal_params = array(21474.83648, -9223372036854.77580, 9223372036854.77580, -21475.83649, -4611686017353.64608, -4611686017353.64608);
$numeric_params = array(0.32768, -21474.83647, 21474.83647, -0.32769, 10737.25440, -10737.25440);
$money_params = array(214748.3648, -92233720368547.5807, 92233720368547.5807, -214758.3649, 46116860173536.608, -46116860173536.608);
$smallmoney_params = array(0, -214748.3647, 214748.3647, 161061.2736, 107374.1824, -107374.1824);
$bit_params = array(0, FALSE, 0, 1, TRUE, 1);
// approximate numerics
$float_params = array(21474.83648, -9223372036.85477, 9223372036.85477, -21475, 4611686017, -4611686017);
$real_params = array(0, -2147.483, 2147.483, 1610, 1073, -1073);
// date and time
$date_params = array('1900-01-01', '0001-01-01', '9999-12-31', '5000-07-15', '2500-04-08', '7500-10-23');
$datetime2_params = array('1900-01-01 00:00:00', '0001-01-01 00:00:00', '9999-12-31 23:59:59.9999999', '5000-07-15 12:30:30.5555', '2500-04-08 06:15:15.33', '7500-10-23 18:45:45.888888');
$datetime_params = array('1900-01-01 00:00:00', '1753-01-01 00:00:00', '9999-12-31 23:59:59.997', '5000-07-15 12:30:30.5', '2500-04-08 06:15:15.33', '7500-10-23 18:45:45.888');
$datetimeoffset_params = array('1900-01-01 00:00:00 +01:00', '0001-01-01 00:00:00 -14:00', '9999-12-31 23:59:59.9999999 +14:00', '5000-07-15 12:30:30.55 -03:00', '2500-04-08 06:15:15.3333 -07:00', '7500-10-23 18:45:45.888888 +07:00');
$smalldatetime_params = array('1900-01-01 00:00:00', '1900-01-01 00:00:00', '2079-06-06 23:59:59', '1990-07-15 12:30:30', '1945-04-08 06:15:15', '2500-10-23 18:45:45');
$time_params = array('00:00:00', '00:00:00.0000000', '23:59:59.9999999', '12:30:30.5555', '06:15:15.33', '18:45:45.888888');
// character strings
$char_params = array('Fixed', '-leng', 'th, n', 'on-Un', 'icode', 'strin');
$varchar_params = array('Variable-length, non-', 'Unicode string data. n', 'defines the string length', 'and can be a value from 1', 'through 8,000.', 'The storage size is the');
$varcharmax_params = array('max indicates that the maximum storage size is 2^31-1 bytes (2 GB)',
'Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.',
'Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.',
'This can create an implicit limit to the number of non-null varchar(max) or nvarchar(max) columns that can be created in a table.',
'No special error is provided when the table is created (beyond the usual warning that the maximum row size exceeds the allowed maximum of 8060 bytes) or at the time of data insertion.',
'This large row size can cause errors (such as error 512) during some normal operations, such as a clustered index key update, or sorts of the full column set, which users cannot anticipate until performing an operation.');
// unicode character strings
$nchar_params = array('Fixed', '-leng', 'th Un', 'icode', 'strin', 'g dat');
$nvarchar_params = array('Variable-length Unicode', 'string data. n defines', 'the string length and can', 'be a value from 1 through', '4,000.', 'The storage size, in');
$nvarcharmax_params = array('max indicates that the maximum storage size is 2^31-1 bytes (2 GB).',
'When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000).',
'Otherwise, the implicit conversion will result in a Unicode large-value (max).',
'Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.',
'This can create an implicit limit to the number of non-null varchar(max) or nvarchar(max) columns that can be created in a table.',
'No special error is provided when the table is created (beyond the usual warning that the maximum row size exceeds the allowed maximum of 8060 bytes) or at the time of data insertion.');
// binary strings
$binary_params = array('Fixed', '-leng', 'th, n', 'on-Un', 'icode', 'strin');
$varbinary_params = array('Variable-length, non-', 'Unicode string data. n', 'defines the string length', 'and can be a value from 1', 'through 8,000.', 'The storage size is the');
$varbinarymax_params = array('max indicates that the maximum storage size is 2^31-1 bytes (2 GB)',
'Use varchar(max) when the sizes of the column data entries vary considerably, and the size might exceed 8,000 bytes.',
'Each non-null varchar(max) or nvarchar(max) column requires 24 bytes of additional fixed allocation which counts against the 8,060 byte row limit during a sort operation.',
'This can create an implicit limit to the number of non-null varchar(max) or nvarchar(max) columns that can be created in a table.',
'No special error is provided when the table is created (beyond the usual warning that the maximum row size exceeds the allowed maximum of 8060 bytes) or at the time of data insertion.', 'This large row size can cause errors (such as error 512) during some normal operations, such as a clustered index key update, or sorts of the full column set, which users cannot anticipate until performing an operation.');
// creates the column names based on data types
// for example, if $dataTypes is array(int, smallint), then the column names are: normint, detint, randint, normsmallint, detsmallint, and randsmallint
// all column names are pushed to the $col_names array
// return a datatypes string used for creating table
function get_dataTypes_str($dataTypes, &$col_names) {
$encTypes = array("norm", "det", "rand");
$dataTypes_str = "";
foreach ($dataTypes as $dataType){
foreach ($encTypes as $encType) {
$col_name = $encType . $dataType;
$dataTypes_str = $dataTypes_str . "[" . $col_name . "] " . $dataType . ", ";
array_push($col_names, $col_name);
}
}
$dataTypes_str = rtrim($dataTypes_str, ", ");
return $dataTypes_str;
}
// encrypts an existing column based on the column names:
// if column name like *norm*, do not encrypts
// if column name like *det*, encrypt using deterministic encryption
// if column name like *rand*, encrypt using randomized encryption
function EncryptColumns($server, $database, $userName, $userPassword, $tbname, $col_names){
$dir_name = realpath(dirname(__FILE__));
$enc_name = $dir_name . DIRECTORY_SEPARATOR . "encrypttable.ps1";
$col_name_str = implode(",", $col_names);
$runCMD = "powershell -executionPolicy Unrestricted -file " . $enc_name . " " . $server . " " . $database . " " . $userName . " " . $userPassword . " " . $tbname . " " . $col_name_str;
shell_exec($runCMD);
}
?>

View file

@ -1,60 +0,0 @@
--TEST--
Test for fetching integer columns with column encryption
--SKIPIF--
--FILE--
<?php
include 'MsCommon.inc';
include 'AEData.inc';
include 'MsSetup.inc';
$conn = Connect(array("ColumnEncryption"=>"Enabled"));
//$conn = Connect();
// create table
$tbname = GetTempTableName("", false);
$dataTypes = array("bigint", "int", "smallint");
$col_names = array();
$dataTypes_str = get_dataTypes_str($dataTypes, $col_names);
CreateTableEx( $conn, $tbname, $dataTypes_str);
// populate table
$data_arr = array_merge( array_slice($bigint_params, 0, 3), array_slice($int_params, 0, 3), array_slice($smallint_params, 0, 3) );
$data_str = implode(", ", $data_arr);
sqlsrv_query( $conn, "INSERT INTO $tbname VALUES ( $data_str )");
// encrypt columns
EncryptColumns($server, $database, $userName, $userPassword, $tbname, $col_names);
//Fetch encrypted values with ColumnEncryption Enabled
$sql = "SELECT * FROM $tbname";
$stmt = sqlsrv_query($conn, $sql);
$decrypted_row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC);
var_dump($decrypted_row);
DropTable($conn, $tbname);
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
?>
--EXPECT--
array(9) {
[0]=>
string(10) "2147483648"
[1]=>
string(19) "-922337203685479936"
[2]=>
string(18) "922337203685479936"
[3]=>
int(32768)
[4]=>
int(-2147483647)
[5]=>
int(2147483647)
[6]=>
int(256)
[7]=>
int(-32767)
[8]=>
int(32767)
}

View file

@ -0,0 +1,32 @@
--TEST--
retrieval of names of column master key and column encryption key generated in the database setup
--SKIPIF--
<?php require('skipif.inc'); ?>
--FILE--
<?php
sqlsrv_configure( 'WarningsReturnAsErrors', 0 );
sqlsrv_configure( 'LogSeverity', SQLSRV_LOG_SEVERITY_ALL );
require( 'MsCommon.inc' );
$conn = Connect();
$query = "SELECT name FROM sys.column_master_keys";
$stmt = sqlsrv_query($conn, $query);
sqlsrv_fetch($stmt);
$master_key_name = sqlsrv_get_field($stmt, 0);
$query = "SELECT name FROM sys.column_encryption_keys";
$stmt = sqlsrv_query($conn, $query);
sqlsrv_fetch($stmt);
$encryption_key_name = sqlsrv_get_field($stmt, 0);
echo "Column Master Key generated: $master_key_name \n";
echo "Column Encryption Key generated: $encryption_key_name \n";
sqlsrv_free_stmt($stmt);
sqlsrv_close( $conn );
?>
--EXPECT--
Column Master Key generated: AEMasterKey
Column Encryption Key generated: AEColumnKey