Removed KSP related scripts and files (#1030)
This commit is contained in:
parent
eb8ecbf6f4
commit
f5c0b63d04
|
@ -1,122 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
#########################################################################################
|
|
||||||
#
|
|
||||||
# Description: This script builds a custom keystore provider and compiles the app that
|
|
||||||
# uses this KSP. Their names can be passed as arguments, but the outputs
|
|
||||||
# are always
|
|
||||||
# - myKSP.dll (myKSPx64.dll) / myKSP.so
|
|
||||||
# - ksp_app.exe / ksp_app
|
|
||||||
#
|
|
||||||
# Requirement:
|
|
||||||
# python 3.x
|
|
||||||
# myKSP.c (or any equivalent)
|
|
||||||
# ksp_app.c (or any equivalent)
|
|
||||||
# msodbcsql.h (odbc header file)
|
|
||||||
#
|
|
||||||
# Execution: Run with command line with optional options
|
|
||||||
# py build_ksp.py --KSP myKSP --APP ksp_app
|
|
||||||
#
|
|
||||||
#############################################################################################
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
# This creates a batch *filename*, which compiles a C program according to
|
|
||||||
# *command* and *arch* (either x86 or x64)
|
|
||||||
def create_batch_file(arch, filename, command):
|
|
||||||
root_dir = 'C:' + os.sep
|
|
||||||
vcvarsall = os.path.join(root_dir, "Program Files (x86)", "Microsoft Visual Studio 14.0", "VC", "vcvarsall.bat")
|
|
||||||
|
|
||||||
try:
|
|
||||||
file = open(filename, 'w')
|
|
||||||
file.write('@ECHO OFF' + os.linesep)
|
|
||||||
if arch == 'x64':
|
|
||||||
file.write('@CALL "' + vcvarsall + '" amd64' + os.linesep)
|
|
||||||
else:
|
|
||||||
file.write('@CALL "' + vcvarsall + '" x86' + os.linesep)
|
|
||||||
|
|
||||||
# compile the code
|
|
||||||
file.write('@CALL ' + command + os.linesep)
|
|
||||||
file.close()
|
|
||||||
except:
|
|
||||||
print('Cannot create ', filename)
|
|
||||||
|
|
||||||
# This invokes the newly created batch file to compile the code,
|
|
||||||
# according to *arch* (either x86 or x64). The batch file will be
|
|
||||||
# removed afterwards
|
|
||||||
def compile_KSP_windows(arch, ksp_src):
|
|
||||||
output = 'myKSP'
|
|
||||||
if arch == 'x64':
|
|
||||||
output = output + arch + '.dll'
|
|
||||||
else:
|
|
||||||
output = output + '.dll'
|
|
||||||
|
|
||||||
command = 'cl {0} /LD /MD /link /out:'.format(ksp_src) + output
|
|
||||||
batchfile = 'build_KSP.bat'
|
|
||||||
create_batch_file(arch, batchfile, command)
|
|
||||||
os.system(batchfile)
|
|
||||||
os.remove(batchfile)
|
|
||||||
|
|
||||||
# This compiles myKSP.c
|
|
||||||
#
|
|
||||||
# In Windows, this will create batch files to compile two dll(s).
|
|
||||||
# Otherwise, this will compile the code and generate a .so file.
|
|
||||||
#
|
|
||||||
# Output: A custom keystore provider created
|
|
||||||
def compile_KSP(ksp_src):
|
|
||||||
print('Compiling ', ksp_src)
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
compile_KSP_windows('x64', ksp_src)
|
|
||||||
compile_KSP_windows('x86', ksp_src)
|
|
||||||
else:
|
|
||||||
os.system('gcc -fshort-wchar -fPIC -o myKSP.so -shared {0}'.format(ksp_src))
|
|
||||||
|
|
||||||
# This compiles ksp app, which assumes the existence of the .dll or the .so file.
|
|
||||||
#
|
|
||||||
# In Windows, a batch file is created in order to compile the code.
|
|
||||||
def configure_KSP(app_src):
|
|
||||||
print('Compiling ', app_src)
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
command = 'cl /MD {0} /link odbc32.lib /out:ksp_app.exe'.format(app_src)
|
|
||||||
batchfile = 'build_app.bat'
|
|
||||||
create_batch_file('x86', batchfile, command)
|
|
||||||
os.system(batchfile)
|
|
||||||
os.remove(batchfile)
|
|
||||||
else:
|
|
||||||
os.system('gcc -o ksp_app -fshort-wchar {0} -lodbc -ldl'.format(app_src))
|
|
||||||
|
|
||||||
################################### Main Function ###################################
|
|
||||||
if __name__ == '__main__':
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument('-ksp', '--KSPSRC', default='myKSP.c', help='The source file of KSP (keystore provider)')
|
|
||||||
parser.add_argument('-app', '--APPSRC', default='ksp_app.c', help='The source file for the app that uses the KSP')
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
ksp_src = args.KSPSRC
|
|
||||||
app_src = args.APPSRC
|
|
||||||
header = 'msodbcsql.h'
|
|
||||||
|
|
||||||
cwd = os.getcwd()
|
|
||||||
|
|
||||||
# make sure all required source and header files are present
|
|
||||||
work_dir = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
os.chdir(work_dir)
|
|
||||||
|
|
||||||
if not os.path.exists(os.path.join(work_dir, header)):
|
|
||||||
print('Error: {0} not found!'.format(header))
|
|
||||||
exit(1)
|
|
||||||
if not os.path.exists(os.path.join(work_dir, ksp_src)):
|
|
||||||
print('Error: {0}.c not found!'.format(ksp_src))
|
|
||||||
exit(1)
|
|
||||||
if not os.path.exists(os.path.join(work_dir, app_src)):
|
|
||||||
print('Error: {0}.c not found!'.format(app_src))
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
compile_KSP(ksp_src)
|
|
||||||
configure_KSP(app_src)
|
|
||||||
|
|
||||||
os.chdir(cwd)
|
|
||||||
|
|
||||||
|
|
|
@ -1,305 +0,0 @@
|
||||||
/******************************************************************************
|
|
||||||
Example application for demonstration of custom keystore provider usage
|
|
||||||
|
|
||||||
Windows: compile with cl /MD ksp_app.c /link odbc32.lib /out:ksp_app.exe
|
|
||||||
Linux/mac: compile with gcc -o ksp_app -fshort-wchar ksp_app.c -lodbc -ldl
|
|
||||||
|
|
||||||
usage: kspapp connstr
|
|
||||||
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#define KSPNAME L"MyCustomKSPName"
|
|
||||||
#define PROV_ENCRYPT_KEY "LPKCWVD07N3RG98J0MBLG4H2" /* this can be any character string */
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#define __stdcall
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#endif
|
|
||||||
#include <sql.h>
|
|
||||||
#include <sqlext.h>
|
|
||||||
#include "msodbcsql.h"
|
|
||||||
|
|
||||||
enum job {
|
|
||||||
set_up = 0,
|
|
||||||
clean_up = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Convenience functions */
|
|
||||||
|
|
||||||
int checkRC(SQLRETURN rc, char *msg, int ret, SQLHANDLE h, SQLSMALLINT ht) {
|
|
||||||
if (rc == SQL_ERROR) {
|
|
||||||
fprintf(stderr, "Error occurred upon %s\n", msg);
|
|
||||||
if (h) {
|
|
||||||
SQLSMALLINT i = 0;
|
|
||||||
SQLSMALLINT outlen = 0;
|
|
||||||
char errmsg[1024];
|
|
||||||
while ((rc = SQLGetDiagField(
|
|
||||||
ht, h, ++i, SQL_DIAG_MESSAGE_TEXT, errmsg, sizeof(errmsg), &outlen)) == SQL_SUCCESS
|
|
||||||
|| rc == SQL_SUCCESS_WITH_INFO) {
|
|
||||||
fprintf(stderr, "Err#%d: %s\n", i, errmsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ret)
|
|
||||||
exit(ret);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (rc == SQL_SUCCESS_WITH_INFO && h) {
|
|
||||||
SQLSMALLINT i = 0;
|
|
||||||
SQLSMALLINT outlen = 0;
|
|
||||||
char errmsg[1024];
|
|
||||||
printf("Success with info for %s:\n", msg);
|
|
||||||
while ((rc = SQLGetDiagField(
|
|
||||||
ht, h, ++i, SQL_DIAG_MESSAGE_TEXT, errmsg, sizeof(errmsg), &outlen)) == SQL_SUCCESS
|
|
||||||
|| rc == SQL_SUCCESS_WITH_INFO) {
|
|
||||||
fprintf(stderr, "Msg#%d: %s\n", i, errmsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void postKspError(CEKEYSTORECONTEXT *ctx, const wchar_t *msg, ...) {
|
|
||||||
if (msg > (wchar_t*)65535)
|
|
||||||
wprintf(L"Provider emitted message: %s\n", msg);
|
|
||||||
else
|
|
||||||
wprintf(L"Provider emitted message ID %d\n", msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
int setKSPLibrary(SQLHSTMT stmt) {
|
|
||||||
unsigned char CEK[32];
|
|
||||||
unsigned char *ECEK;
|
|
||||||
unsigned short ECEKlen;
|
|
||||||
unsigned char foundProv = 0;
|
|
||||||
int i;
|
|
||||||
#ifdef _WIN32
|
|
||||||
HMODULE hProvLib;
|
|
||||||
#else
|
|
||||||
void *hProvLib;
|
|
||||||
#endif
|
|
||||||
CEKEYSTORECONTEXT ctx = {0};
|
|
||||||
CEKEYSTOREPROVIDER **ppKsp, *pKsp;
|
|
||||||
int(__stdcall *pEncryptCEK)(CEKEYSTORECONTEXT *, errFunc *, unsigned char *, unsigned short, unsigned char **, unsigned short *);
|
|
||||||
|
|
||||||
/* Load the provider library */
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (!(hProvLib = LoadLibrary("myKSP.dll"))) {
|
|
||||||
#else
|
|
||||||
if (!(hProvLib = dlopen("./myKSP.so", RTLD_NOW))) {
|
|
||||||
#endif
|
|
||||||
fprintf(stderr, "Error loading KSP library\n");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (!(ppKsp = (CEKEYSTOREPROVIDER**)GetProcAddress(hProvLib, "CEKeystoreProvider"))) {
|
|
||||||
#else
|
|
||||||
if (!(ppKsp = (CEKEYSTOREPROVIDER**)dlsym(hProvLib, "CEKeystoreProvider"))) {
|
|
||||||
#endif
|
|
||||||
fprintf(stderr, "The export CEKeystoreProvider was not found in the KSP library\n");
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
while (pKsp = *ppKsp++) {
|
|
||||||
if (!memcmp(KSPNAME, pKsp->Name, sizeof(KSPNAME))) {
|
|
||||||
foundProv = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (! foundProv) {
|
|
||||||
fprintf(stderr, "Could not find provider in the library\n");
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pKsp->Init && !pKsp->Init(&ctx, postKspError)) {
|
|
||||||
fprintf(stderr, "Could not initialize provider\n");
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (!(pEncryptCEK = (LPVOID)GetProcAddress(hProvLib, "KeystoreEncrypt"))) {
|
|
||||||
#else
|
|
||||||
if (!(pEncryptCEK = dlsym(hProvLib, "KeystoreEncrypt"))) {
|
|
||||||
#endif
|
|
||||||
fprintf(stderr, "The export KeystoreEncrypt was not found in the KSP library\n");
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
if (!pKsp->Write) {
|
|
||||||
fprintf(stderr, "Provider does not support configuration\n");
|
|
||||||
return 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Configure the provider with the key */
|
|
||||||
if (!pKsp->Write(&ctx, postKspError, PROV_ENCRYPT_KEY, strlen(PROV_ENCRYPT_KEY))) {
|
|
||||||
fprintf(stderr, "Error writing to KSP\n");
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate a CEK and encrypt it with the provider */
|
|
||||||
srand(time(0) ^ getpid());
|
|
||||||
for (i = 0; i < sizeof(CEK); i++)
|
|
||||||
CEK[i] = rand();
|
|
||||||
|
|
||||||
if (!pEncryptCEK(&ctx, postKspError, CEK, sizeof(CEK), &ECEK, &ECEKlen)) {
|
|
||||||
fprintf(stderr, "Error encrypting CEK\n");
|
|
||||||
return 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a CMK definition on the server */
|
|
||||||
{
|
|
||||||
static char cmkSql[] = "CREATE COLUMN MASTER KEY CustomCMK WITH ("
|
|
||||||
"KEY_STORE_PROVIDER_NAME = 'MyCustomKSPName',"
|
|
||||||
"KEY_PATH = 'TheOneAndOnlyKey')";
|
|
||||||
printf("Create CMK: %s\n", cmkSql);
|
|
||||||
SQLExecDirect(stmt, cmkSql, SQL_NTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a CEK definition on the server */
|
|
||||||
{
|
|
||||||
const char cekSqlBefore[] = "CREATE COLUMN ENCRYPTION KEY CustomCEK WITH VALUES ("
|
|
||||||
"COLUMN_MASTER_KEY = CustomCMK,"
|
|
||||||
"ALGORITHM = 'none',"
|
|
||||||
"ENCRYPTED_VALUE = 0x";
|
|
||||||
char *cekSql = malloc(sizeof(cekSqlBefore) + 2 * ECEKlen + 2); /* 1 for ')', 1 for null terminator */
|
|
||||||
strcpy(cekSql, cekSqlBefore);
|
|
||||||
for (i = 0; i < ECEKlen; i++)
|
|
||||||
sprintf(cekSql + sizeof(cekSqlBefore) - 1 + 2 * i, "%02x", ECEK[i]);
|
|
||||||
strcat(cekSql, ")");
|
|
||||||
printf("Create CEK: %s\n", cekSql);
|
|
||||||
SQLExecDirect(stmt, cekSql, SQL_NTS);
|
|
||||||
free(cekSql);
|
|
||||||
#ifdef _WIN32
|
|
||||||
LocalFree(ECEK);
|
|
||||||
#else
|
|
||||||
free(ECEK);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
FreeLibrary(hProvLib);
|
|
||||||
#else
|
|
||||||
dlclose(hProvLib);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void populateTestTable(SQLHDBC dbc, SQLHSTMT stmt)
|
|
||||||
{
|
|
||||||
SQLRETURN rc;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
/* Create a table with encrypted columns */
|
|
||||||
{
|
|
||||||
static char *tableSql = "CREATE TABLE CustomKSPTestTable ("
|
|
||||||
"c1 int,"
|
|
||||||
"c2 varchar(255) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK, ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'),"
|
|
||||||
"c3 char(5) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK, ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'),"
|
|
||||||
"c4 date ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = CustomCEK, ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'))";
|
|
||||||
printf("Create table: %s\n", tableSql);
|
|
||||||
SQLExecDirect(stmt, tableSql, SQL_NTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load provider into the ODBC Driver and configure it */
|
|
||||||
{
|
|
||||||
unsigned char ksd[sizeof(CEKEYSTOREDATA) + sizeof(PROV_ENCRYPT_KEY) - 1];
|
|
||||||
CEKEYSTOREDATA *pKsd = (CEKEYSTOREDATA*)ksd;
|
|
||||||
pKsd->name = L"MyCustomKSPName";
|
|
||||||
pKsd->dataSize = sizeof(PROV_ENCRYPT_KEY) - 1;
|
|
||||||
memcpy(pKsd->data, PROV_ENCRYPT_KEY, sizeof(PROV_ENCRYPT_KEY) - 1);
|
|
||||||
#ifdef _WIN32
|
|
||||||
rc = SQLSetConnectAttr(dbc, SQL_COPT_SS_CEKEYSTOREPROVIDER, "myKSP.dll", SQL_NTS);
|
|
||||||
#else
|
|
||||||
rc = SQLSetConnectAttr(dbc, SQL_COPT_SS_CEKEYSTOREPROVIDER, "./myKSP.so", SQL_NTS);
|
|
||||||
#endif
|
|
||||||
checkRC(rc, "Loading KSP into ODBC Driver", 7, dbc, SQL_HANDLE_DBC);
|
|
||||||
rc = SQLSetConnectAttr(dbc, SQL_COPT_SS_CEKEYSTOREDATA, (SQLPOINTER)pKsd, SQL_IS_POINTER);
|
|
||||||
checkRC(rc, "Configuring the KSP", 7, dbc, SQL_HANDLE_DBC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert some data */
|
|
||||||
{
|
|
||||||
int c1;
|
|
||||||
char c2[256];
|
|
||||||
char c3[6];
|
|
||||||
SQL_DATE_STRUCT date;
|
|
||||||
SQLLEN cbdate;
|
|
||||||
rc = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &c1, 0, 0);
|
|
||||||
checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT);
|
|
||||||
rc = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 255, 0, c2, 255, 0);
|
|
||||||
checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT);
|
|
||||||
rc = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 5, 0, c3, 5, 0);
|
|
||||||
checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT);
|
|
||||||
checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT);
|
|
||||||
cbdate = sizeof(SQL_DATE_STRUCT);
|
|
||||||
rc = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_TYPE_DATE, SQL_TYPE_DATE, 10, 0, &date, 0, &cbdate);
|
|
||||||
checkRC(rc, "Binding parameters for insert", 9, stmt, SQL_HANDLE_STMT);
|
|
||||||
|
|
||||||
date.year = 2017;
|
|
||||||
date.month = 8;
|
|
||||||
for (i = 0; i < 10; i++) {
|
|
||||||
date.day = i + 10;
|
|
||||||
|
|
||||||
c1 = i * 10 + i + 1;
|
|
||||||
sprintf(c2, "Sample data %d for column 2", i);
|
|
||||||
for (j = 0; j < 3; j++) {
|
|
||||||
c3[j] = 'a' + i + j;
|
|
||||||
}
|
|
||||||
c3[3] = '\0';
|
|
||||||
rc = SQLExecDirect(stmt, "INSERT INTO CustomKSPTestTable (c1, c2, c3, c4) values (?, ?, ?, ?)", SQL_NTS);
|
|
||||||
checkRC(rc, "Inserting rows query", 10, stmt, SQL_HANDLE_STMT);
|
|
||||||
}
|
|
||||||
printf("(Encrypted) data has been inserted into CustomKSPTestTable. You may inspect the data now.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
char sqlbuf[1024];
|
|
||||||
SQLHENV env;
|
|
||||||
SQLHDBC dbc;
|
|
||||||
SQLHSTMT stmt;
|
|
||||||
SQLRETURN rc;
|
|
||||||
int i;
|
|
||||||
char connStr[1024];
|
|
||||||
enum job task;
|
|
||||||
|
|
||||||
if (argc < 6) {
|
|
||||||
fprintf(stderr, "usage: kspapp job server database uid pwd\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
task = atoi(argv[1]);
|
|
||||||
|
|
||||||
sprintf(connStr, "DRIVER={ODBC Driver 17 for SQL Server};SERVER=%s;ColumnEncryption=Enabled;DATABASE=%s;UID=%s;PWD=%s", argv[2], argv[3], argv[4], argv[5]);
|
|
||||||
|
|
||||||
/* Connect to Server */
|
|
||||||
rc = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &env);
|
|
||||||
checkRC(rc, "allocating environment handle", 2, 0, 0);
|
|
||||||
rc = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
|
|
||||||
checkRC(rc, "setting ODBC version to 3.0", 3, env, SQL_HANDLE_ENV);
|
|
||||||
rc = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
|
|
||||||
checkRC(rc, "allocating connection handle", 4, env, SQL_HANDLE_ENV);
|
|
||||||
rc = SQLDriverConnect(dbc, 0, connStr, strlen(connStr), NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
|
|
||||||
checkRC(rc, "connecting to data source", 5, dbc, SQL_HANDLE_DBC);
|
|
||||||
rc = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
|
|
||||||
checkRC(rc, "allocating statement handle", 6, dbc, SQL_HANDLE_DBC);
|
|
||||||
|
|
||||||
if (task == set_up) {
|
|
||||||
printf("Setting up KSP...\n");
|
|
||||||
setKSPLibrary(stmt);
|
|
||||||
populateTestTable(dbc, stmt);
|
|
||||||
}
|
|
||||||
else if (task == clean_up) {
|
|
||||||
printf("Cleaning up KSP...\n");
|
|
||||||
|
|
||||||
SQLExecDirect(stmt, "DROP TABLE CustomKSPTestTable", SQL_NTS);
|
|
||||||
SQLExecDirect(stmt, "DROP COLUMN ENCRYPTION KEY CustomCEK", SQL_NTS);
|
|
||||||
SQLExecDirect(stmt, "DROP COLUMN MASTER KEY CustomCMK", SQL_NTS);
|
|
||||||
printf("Removed table, CEK, and CMK\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
SQLDisconnect(dbc);
|
|
||||||
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
|
|
||||||
SQLFreeHandle(SQL_HANDLE_ENV, env);
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
/******************************************************************************
|
|
||||||
Custom Keystore Provider Example
|
|
||||||
|
|
||||||
Windows: compile with cl myKSP.c /LD /MD /link /out:myKSP.dll
|
|
||||||
Linux/mac: compile with gcc -fshort-wchar -fPIC -o myKSP.so -shared myKSP.c
|
|
||||||
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#else
|
|
||||||
#define __stdcall
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DEBUG 0
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sqltypes.h>
|
|
||||||
#include <sql.h>
|
|
||||||
#include <sqlext.h>
|
|
||||||
#include "msodbcsql.h"
|
|
||||||
|
|
||||||
int wcscmp_short(wchar_t *s1, wchar_t *s2) {
|
|
||||||
while(*s1 && *s2 && *s1 == *s2)
|
|
||||||
s1++, s2++;
|
|
||||||
return *s1 - *s2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int __stdcall KeystoreInit(CEKEYSTORECONTEXT *ctx, errFunc *onError) {
|
|
||||||
if (DEBUG)
|
|
||||||
printf("KSP Init() function called\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned char *g_encryptKey;
|
|
||||||
static unsigned int g_encryptKeyLen;
|
|
||||||
|
|
||||||
int __stdcall KeystoreWrite(CEKEYSTORECONTEXT *ctx, errFunc *onError, void *data, unsigned int len) {
|
|
||||||
if (DEBUG)
|
|
||||||
printf("KSP Write() function called (%d bytes)\n", len);
|
|
||||||
if (len) {
|
|
||||||
if (g_encryptKey)
|
|
||||||
free(g_encryptKey);
|
|
||||||
g_encryptKey = malloc(len);
|
|
||||||
if (!g_encryptKey) {
|
|
||||||
onError(ctx, L"Memory Allocation Error");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
memcpy(g_encryptKey, data, len);
|
|
||||||
g_encryptKeyLen = len;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Very simple "encryption" scheme - rotating XOR with the key
|
|
||||||
int __stdcall KeystoreDecrypt(CEKEYSTORECONTEXT *ctx, errFunc *onError, const wchar_t *keyPath, const wchar_t *alg, unsigned char *ecek, unsigned short ecekLen, unsigned char **cekOut, unsigned short *cekLen) {
|
|
||||||
unsigned int i;
|
|
||||||
if (DEBUG)
|
|
||||||
printf("KSP Decrypt() function called (keypath=%S alg=%S ecekLen=%u)\n", keyPath, alg, ecekLen);
|
|
||||||
if (wcscmp_short(keyPath, L"TheOneAndOnlyKey")) {
|
|
||||||
onError(ctx, L"Invalid key path");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (wcscmp_short(alg, L"none")) {
|
|
||||||
onError(ctx, L"Invalid algorithm");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!g_encryptKey) {
|
|
||||||
onError(ctx, L"Keystore provider not initialized with key");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#ifndef _WIN32
|
|
||||||
*cekOut = malloc(ecekLen);
|
|
||||||
#else
|
|
||||||
*cekOut = LocalAlloc(LMEM_FIXED, ecekLen);
|
|
||||||
#endif
|
|
||||||
if (!*cekOut) {
|
|
||||||
onError(ctx, L"Memory Allocation Error");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*cekLen = ecekLen;
|
|
||||||
for (i = 0; i < ecekLen; i++)
|
|
||||||
(*cekOut)[i] = ecek[i] ^ g_encryptKey[i % g_encryptKeyLen];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note that in the provider interface, this function would be referenced via the CEKEYSTOREPROVIDER
|
|
||||||
// structure. However, that does not preclude keystore providers from exporting their own functions,
|
|
||||||
// as illustrated by this example where the encryption is performed via a separate function (with a
|
|
||||||
// different prototype than the one in the KSP interface.)
|
|
||||||
#ifdef _WIN32
|
|
||||||
__declspec(dllexport)
|
|
||||||
#endif
|
|
||||||
int KeystoreEncrypt(CEKEYSTORECONTEXT *ctx, errFunc *onError,
|
|
||||||
unsigned char *cek, unsigned short cekLen,
|
|
||||||
unsigned char **ecekOut, unsigned short *ecekLen) {
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
if (DEBUG)
|
|
||||||
printf("KSP Encrypt() function called (cekLen=%u)\n", cekLen);
|
|
||||||
if (!g_encryptKey) {
|
|
||||||
onError(ctx, L"Keystore provider not initialized with key");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*ecekOut = malloc(cekLen);
|
|
||||||
if (!*ecekOut) {
|
|
||||||
onError(ctx, L"Memory Allocation Error");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*ecekLen = cekLen;
|
|
||||||
for (i = 0; i < cekLen; i++)
|
|
||||||
(*ecekOut)[i] = cek[i] ^ g_encryptKey[i % g_encryptKeyLen];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
CEKEYSTOREPROVIDER MyCustomKSPName_desc = {
|
|
||||||
L"MyCustomKSPName",
|
|
||||||
KeystoreInit,
|
|
||||||
0,
|
|
||||||
KeystoreWrite,
|
|
||||||
KeystoreDecrypt,
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
__declspec(dllexport)
|
|
||||||
#endif
|
|
||||||
CEKEYSTOREPROVIDER *CEKeystoreProvider[] = {
|
|
||||||
&MyCustomKSPName_desc,
|
|
||||||
0
|
|
||||||
};
|
|
|
@ -1,57 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
#########################################################################################
|
|
||||||
#
|
|
||||||
# Description: This script assumes the existence of the ksp_app executable and will
|
|
||||||
# invoke it to create / remove the Column Master Key, the Column Encryption key,
|
|
||||||
# and the table [CustomKSPTestTable] in the test database.
|
|
||||||
#
|
|
||||||
# Requirement:
|
|
||||||
# python 3.x
|
|
||||||
# ksp_app executable
|
|
||||||
#
|
|
||||||
# Execution: Run with command line with required options
|
|
||||||
# py run_ksp.py --SERVER=server --DBNAME=database --UID=uid --PWD=pwd
|
|
||||||
# py run_ksp.py --SERVER=server --DBNAME=database --UID=uid --PWD=pwd --REMOVE
|
|
||||||
#
|
|
||||||
#############################################################################################
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
################################### Main Function ###################################
|
|
||||||
if __name__ == '__main__':
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument('-server', '--SERVER', required=True, help='SQL Server')
|
|
||||||
parser.add_argument('-dbname', '--DBNAME', required=True, help='Name of an existing database')
|
|
||||||
parser.add_argument('-uid', '--UID', required=True, help='User name')
|
|
||||||
parser.add_argument('-pwd', '--PWD', required=True, help='User password')
|
|
||||||
parser.add_argument('-remove', '--REMOVE', action='store_true', help='Clean up KSP related data, false by default')
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
app_name = 'ksp_app'
|
|
||||||
cwd = os.getcwd()
|
|
||||||
|
|
||||||
# first check if the ksp app is present
|
|
||||||
work_dir = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
os.chdir(work_dir)
|
|
||||||
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
path = os.path.join(work_dir, app_name + '.exe')
|
|
||||||
executable = app_name
|
|
||||||
else:
|
|
||||||
path = os.path.join(work_dir, app_name)
|
|
||||||
executable = './' + app_name
|
|
||||||
|
|
||||||
if not os.path.exists(path):
|
|
||||||
print('Error: {0} not found!'.format(path))
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
if args.REMOVE:
|
|
||||||
os.system('{0} 1 {1} {2} {3} {4}'.format(executable, args.SERVER, args.DBNAME, args.UID, args.PWD))
|
|
||||||
else:
|
|
||||||
os.system('{0} 0 {1} {2} {3} {4}'.format(executable, args.SERVER, args.DBNAME, args.UID, args.PWD))
|
|
||||||
|
|
||||||
os.chdir(cwd)
|
|
Loading…
Reference in a new issue