Example Code

Updated: June 7, 2018

SmartKey provides multiple interfaces to application developers. For C/C++ programmers, SmartKey provides a PKCS#11 interface through a library. For Java programmers, SmartKey can be accessed through the JCE interface. SmartKey can also be accessed through its RESTful interface, documented at http://support.smartkey.io/api/index.html

We provide examples for using SmartKey in 3 languages – a C++ program using the PKCS#11 interface, a Java program using the JCE interface, and a Python program using the REST interface.

Download the code to initialize and login. The example programs can be downloaded in full at http://support.smartkey.io/smartkey/resources.html

Initialization and Login

C++


CK_FUNCTION_LIST_PTR initialize() {
    CK_FUNCTION_LIST_PTR p11;
    void *pDynLib;

    pDynLib = dlopen("/opt/fortanix/pkcs11/sdkms-pkcs11.so", RTLD_NOW);
    if (!pDynLib) {
        cout << "Failed to load the PKCS#11 library" << endl;
        return NULL;
    }
    cout << "Successfully initialized PKCS#11 library to use SmartKey" << endl;
    CK_C_GetFunctionList pGetFunctionList = (CK_C_GetFunctionList) dlsym(pDynLib, "C_GetFunctionList");
    (*pGetFunctionList)(&p11);
    return p11;
}

CK_RV login(CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE_PTR phSession, string pin) {
    CK_RV rv;
    CK_SLOT_ID slotId = 1;

    rv = p11->C_Initialize(NULL_PTR);
    if (rv == CKR_OK) {
        rv = p11->C_OpenSession(slotId, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, phSession);
        if (rv == CKR_OK) rv = p11->C_Login(*phSession, CKU_USER, (CK_UTF8CHAR_PTR)pin.c_str(), pin.length());
    }
    if (rv != CKR_OK) {
        cout << "Incorrect API Key. Error code = " << rv << endl;
    } else {
        cout << "Successfully logged in to SmartKey" << endl << endl;
    }
    return rv;
}

Java


private static Provider initialize() {
    try {
        final Path tmpFile = Files.createTempFile("pkcs11", ".cfg");
        tmpFile.toFile().deleteOnExit();
        final List lines = Arrays.asList("name = fortanix", "library = /opt/fortanix/pkcs11/sdkms-pkcs11.so");
        Files.write(tmpFile, lines, Charset.defaultCharset(), StandardOpenOption.WRITE);

        Provider provider = new sun.security.pkcs11.SunPKCS11(tmpFile.toString());
        System.out.println("Successfully initialized JCE to use SmartKey");
        return provider;
    } catch (Exception e) {
        System.out.println("Could not initialize: " + e);
        return null;
    }
}

private static boolean login(Provider provider, String apiKey) {
    try {
        KeyStore ks = KeyStore.getInstance("PKCS11", provider);
        ks.load(null, apiKey.toCharArray());
        System.out.println("Successfully logged in to SmartKey");
        return true;
    } catch (Exception e) {
        System.out.println("Incorrect API Key: " + e);
        return false;
    }
}

Python


def login(api_key):
    res = requests.request(method='POST',
                           url="https://www.smartkey.io/sys/v1/session/auth",
                           headers={'Authorization' : 'Basic ' + api_key})
    if res.status_code != requests.codes.ok:
        print "Can't login: " + str(res.status_code) + ": " + res.text + " to " + FORTANIX_API_ENDPOINT
        return None
    else:
        print "Successfully logged in to SmartKey"
        return res.json()['access_token']

Creating a key

C++


CK_OBJECT_HANDLE generate_key(CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE hSession, CK_ULONG len) {
    CK_RV rv;
    CK_MECHANISM mechKeyGen = {
      CKM_AES_KEY_GEN, NULL_PTR, 0
    };
    CK_BBOOL _true = CK_TRUE;
    CK_OBJECT_HANDLE hKey;

    CK_ATTRIBUTE keyTemplate[] = {
      {CKA_VALUE_LEN, &len, sizeof(len)},
      {CKA_ENCRYPT, &_true, sizeof(_true)},
      {CKA_DECRYPT, &_true, sizeof(_true)}
    };

    rv = p11->C_GenerateKey(hSession, &mechKeyGen, keyTemplate, sizeof(keyTemplate)/sizeof(*keyTemplate), &hKey);
    if (rv == CKR_OK) return hKey; else return CK_INVALID_HANDLE;
}

Java


private static SecretKey generateKey(Provider provider, String type, int length) {
    try {
        KeyGenerator keyGen = KeyGenerator.getInstance(type, provider);
        keyGen.init(length);
        SecretKey key = keyGen.generateKey();
        System.out.println("Successfully generated secret key of type " + type + " and length " + length);
        return key;
    } catch (Exception e) {
        System.out.println("Can't generate secret key: " + e);
        return null;
    }
}

Python


def generate_key(bearer_token, name, description, type, length):
    key_request = {'name': name, 'description': description, 'obj_type': type, 'key_size': length}
    res = requests.request(method='POST',
                           url="https://www.smartkey.io/crypto/v1/keys",
                           headers={'Authorization' : 'Bearer ' + bearer_token},
                           data=json.dumps(key_request))
    if res.status_code != requests.codes.created:
        print "Can't generate secret key: " + str(res.status_code)
        return None
    else:
        print "Successfully generated secret key"
        return res.json()['kid']

Encryption

C++


string encrypt(CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey, string plain) {
    CK_RV rv;
    CK_BYTE *iv;
    CK_ULONG iv_len;
    string iv_b64;
    CK_BYTE *cipher;
    CK_ULONG cipher_len;
    string cipher_b64;

    iv_len = (CK_ULONG) AES_KEYLENGTH/8;
    iv = (CK_BYTE *)malloc(iv_len * sizeof(CK_BYTE));
    CK_MECHANISM mechanism = {
      CKM_AES_CBC_PAD, iv, iv_len
    };
    Base64::Encode(string((char *)iv, iv_len), &iv_b64);

    rv = p11->C_EncryptInit(hSession, &mechanism, hKey);
    if (rv == CKR_OK) {
        rv = p11->C_Encrypt(hSession, (CK_BYTE_PTR) plain.c_str(), plain.length(), NULL, &cipher_len);
        if (rv == CKR_OK) {
            cipher = (CK_BYTE *)malloc(cipher_len * sizeof(CK_BYTE));
            rv = p11->C_Encrypt(hSession, (CK_BYTE_PTR) plain.c_str(), plain.length(), cipher, &cipher_len);
        }
    }
    if (rv != CKR_OK) {
        cout << "Encryption failed. Error code = " << rv << endl;
        return string();
    }
    Base64::Encode(string((char *)cipher, cipher_len), &cipher_b64);
    return iv_b64 + ":" + cipher_b64;
}

Java


private static String encrypt(Provider provider, SecretKey key, String plain, String mode, int length) {
    byte[] iv = new byte[length / 8];
    SecureRandom prng = new SecureRandom();
    prng.nextBytes(iv);

    try {
        Cipher cipher = Cipher.getInstance(mode, provider);
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
        byte[] byteCipherText = cipher.doFinal(plain.getBytes());
        String cryptStruct = new Base64().encodeAsString(iv) + ":" + new Base64().encodeAsString(byteCipherText);
        return cryptStruct;
    } catch (Exception e) {
        System.out.println("Encryption failed: " + e);
        return null;
    }
}
          

Python


def encrypt(bearer_token, kid, plain, type, mode):
    iv = base64.b64encode(bytearray(random.sample(range(1,100),AES_KEYLENGTH/8)))
    encrypt_request = {'plain': base64.b64encode(plain), 'alg': type, 'mode': mode, 'iv': iv}
    res = requests.request(method='POST',
                           url="https://www.smartkey.io/crypto/v1/keys/" + kid + "/encrypt",
                           headers={'Authorization' : 'Bearer ' + bearer_token},
                           data=json.dumps(encrypt_request))
    if res.status_code != requests.codes.ok:
        print "Can't encrypt: " + str(res.status_code)
        return None
    else:
        return res.json()['iv'] + ':' + res.json()['cipher']
                  

Decryption

C++


string decrypt(CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey, string iv_cipher) {
    CK_RV rv;
    CK_BYTE *plain;
    CK_ULONG plain_len;
    string iv;
    string cipher;

    Base64::Decode(iv_cipher.substr(0, iv_cipher.find(':')), &iv);
    CK_MECHANISM mechanism = {
      CKM_AES_CBC_PAD, (CK_BYTE_PTR) iv.c_str(), iv.length()
    };

    rv = p11->C_DecryptInit(hSession, &mechanism, hKey);
    if (rv == CKR_OK) {
	      Base64::Decode(iv_cipher.substr(iv_cipher.find(':')+1, iv_cipher.length() - iv_cipher.find(':') + 1), &cipher);
        rv = p11->C_Decrypt(hSession, (CK_BYTE_PTR) cipher.c_str(), cipher.length(), NULL, &plain_len);
        if (rv == CKR_OK) {
			      plain = (CK_BYTE *)malloc(plain_len * sizeof(CK_BYTE));
            rv = p11->C_Decrypt(hSession, (CK_BYTE_PTR) cipher.c_str(), cipher.length(), plain, &plain_len);
        }
    }
    if (rv != CKR_OK) {
        cout << "Decryption failed. Error code = " << rv << endl;
				return string();
    }
    return string((char*)plain, plain_len);
}
                  

Java


private static String decrypt(Provider provider, SecretKey key, String cipherStruct, String mode) {
    try {
        String[] ivAndCipherText = cipherStruct.split(":");
        byte[] iv = new Base64().decode(ivAndCipherText[0]);
        byte[] cipherText = new Base64().decode(ivAndCipherText[1]);
        Cipher cipher = Cipher.getInstance(mode, provider);
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
        byte[] bytePlainText = cipher.doFinal(cipherText);

        return new String(bytePlainText);
    } catch (Exception e) {
        System.out.println("Decryption failed: " + e);
        return null;
    }
}
                  

Python


def decrypt(bearer_token, kid, iv_cipher, type, mode):
    iv, cipher = iv_cipher.split(':')
    decrypt_request = {'cipher': cipher, 'alg': type, 'mode': mode, 'iv': iv}
    res = requests.request(method='POST',
                           url="https://www.smartkey.io/crypto/v1/keys/" + kid + "/decrypt",
                           headers={'Authorization' : 'Bearer ' + bearer_token},
                           data=json.dumps(decrypt_request))
    if res.status_code != requests.codes.ok:
        print "Can't decrypt: " + str(res.status_code)
        return None
    else:
        return base64.b64decode(res.json()['plain'])
                          

Deleting a key

C++


CK_RV delete_key(CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey) {
	return p11->C_DestroyObject(hSession, hKey);
}
                          

Java


private static boolean delete_key(KeyStore ks, String alias) {
        try {
            ks.deleteEntry(alias);
            return true;
        } catch (Exception e) {
            System.out.println("Can't delete key " + alias + ": " + e);
            return false;
        }
    }
                              

Python


def delete_key(bearer_token, kid):
    res = requests.request(method='DELETE',
                           url="https://www.smartkey.io/crypto/v1/keys/" + kid,
                           headers={'Authorization' : 'Bearer ' + bearer_token})
    if res.status_code != requests.codes.no_content:
        print "Can't delete key: " + str(res.status_code)
    else:
        print "Deleted Key"
                                  

Log out

C++


CK_RV logout(CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE hSession) {
	return p11->C_Logout(hSession);
}
                                  

Java


private static boolean logout(Provider provider) {
    try {
        ((AuthProvider) provider).logout();
        return true;
    } catch (Exception e) {
        System.out.println("Can't logout: " + e);
        return false;
    }
}
                                  

Python


def logout(bearer_token):
    res = requests.request(method='POST',
                           url="https://www.smartkey.io/sys/v1/session/terminate",
                           headers={'Authorization' : 'Bearer ' + bearer_token})
    if res.status_code != requests.codes.no_content:
        print "Can't logout: " + str(res.status_code)
    else:
        print "Logged out"