Encryption as a Service SDK for .NET/C# 

The IDENTOS SDK allows you to secure application data and enables applications to encrypt, decrypt and share access to data across multiple devices and users. IDENTOS provides simple interfaces to register a device to your application, authenticate your users, and access the data protected by our encryption key management system.

Main functions of the SDK:

Register a Device
An application must register the user and device before the IDENTOS service can be initialized. When the device is registered, it is associated to the application and user and is subsequently governed by the key management policies set by the administrator.

Authenticate & Authorize
IDENTOS provides the ability to enforce a PIN entry upon application launch to ensure the user is authenticated. This PIN helps to secure the user's private key which is used to protect data and digitally sign requests for keys. The PIN can be set to 0 to disable PIN Required as a feature, however this is not recommended. 

Control access to data
Encrypt and decrypt any given piece of data, grant users access to the encryption keys, and maintain compliance by logging every request for data and keys.


Getting Started

Download the SDK

Contact us to request the SDK

Install the Framework

In Visual Studio:

1. Make IdentosSDK.dll a project reference. This contains the Csharp interface code to be used in your project.
2. Add identos.dll to the project. Under Properties, 'Copy to Output Directory' must be 'Copy Always'. This contains the code implementation used by IdentosSDK.dll.
3. Add libeay32.dll to the project. Under Properties, 'Copy to Output Directory' must be 'Copy Always'
4. Add ssleay32.dll to the project. Under Properties, 'Copy to Output Directory' must be 'Copy Always'
5. Add fidouaf.dll to the project. Under Properties, 'Copy to Output Directory' must be 'Copy Always'

Initialize the SDK

You can find your appId and clientKey on your app’s admin page.

/**
Initialize the Identos SDK

This is always the first to the SDK

@param appId - Your app id, provided by Identos
@param clientKey - Your client key, provided by Identos
@param version - Your app version, allows different security policies based on version
@param livemode - `true` to use live Identos trusted server, `false` to use sandbox Identos trusted server
@param path – app directory, this is where identos generated files are kept
@return IdentosStatus

*/
IdentosStatus initializeStatus = (IdentosStatus)identos.initialize(IdentosAppId, IdentosClientKey, IdentosAppVersion, false, username);
Console.WriteLine("Identos: initialize: " + initializeStatus);

// Depending on the status we will either register this device, or display the main menu
if (initializeStatus == IdentosStatus.Success)
{
// authenticate the user
if (authenticateUser() == true)
{
// if authenticated, show main menu until quit
}
else
{
// failed to authenticate
}
}
else if (initializeStatus == IdentosStatus.DeviceUnregistered)
{
// device unknown by Identos Server, register the device
registerDevice();
}
else
{
// failure state
}
`

Authentication

Authentication allows access to IDENTOS functions such as encryption, decryption, and granting access to private keys. Authentication will not succeed unless a device has been registered.

User PIN

An optional feature, requiring the user to enter a PIN provides the second authentication factor (what the user knows) which helps protect the device’s private key at rest. You should request the PIN just in time to use it, and not keep it around longer than necessary.

Depending on the configuration of your app, a user supplied PIN may be required during steps such as registering a user device, authentication, or data encryption functions.

After initialization authentication is done to authenticate device with Identos. If device is unregistered, Identos will both authenticate the device and create a temporary user, returning a registration_token. The application's server can transfer this unregistered device to a real user to complete registration using the user/register endpoint with the registration_token.

/**
Authenticate with Identos.

If the device is is unregistered, Identos will create a temporary user.
The app can then query for the registration token from Identos.

@param pin - The PIN used during the device registration

@return authentication status
*/
IdentosStatus authStatus = (IdentosStatus)identos.authenticate(passphrase);
Console.WriteLine("Authentication result: " + authStatus);
/**
Get registration token from Identos.

@return registration_token
*/

string registration_token = identos.registration_token();

Back End

On your server, register the user by using the registration token from the client

POST user/register

Purpose

Register a new user with the trusted server. Usernames must be unique in your application. If a username already exists, an additional device is added to that username.

Request

{
appid : "an-app-id"
serverkey : "a-server-key"
username : "a-username"
device-token : "a-registration-token"
}

Response

HTTP 200

{ "userid" : "a-userid" }

Curl Example

#! /bin/bash

curl -X POST \
-H "Content-Type: application/json" \
-d '{
"appid": "an-app-id",
"serverkey": "a-server-key",
"username": "a-username",
"device-token": "a-registration-token"
}' \
https://sandbox.identos.ca

One Time Password

Coming soon!


Encryption Functions

Encryption functions include encryption of data, the decryption of data, and granting user access. These functions only succeed after the application has been successfully authenticated.

Interface

/**
Identos Return Data class
This holds the en/decrypted data along with its key identifier, it is the result of all crypto operations

*/
namespace com.identos {

public class identos_return_data : global::System.IDisposable {

public int status

public string identifier

public string data64

}

}

/**
encrypt plaintext

@param plaintext Bytes to encrypt
@param identifier Optional key identifier

@return return data class
*/
public identos_return_data encrypt(byte[] plaintext, string identifier)


/**
decrypt ciphertext

@param ciphertext64 Ciphertext to decrypt, this was the .data64 property returned from an Identos.encrypt operation

@return return data class
*/
public identos_return_data decrypt(string ciphertext64)


/**
grant user access

@param identifier Key identifier to grant access too
@param to_userid User id to grant access to, id from user/device pair registration (server side)

@return return data class
*/
public int grant(string identifier, string to_userid)

/**
Sign arbitrary data with this users private key

@param data, data message to be signed

@return identos_return_data
*/
public identos_return_data sign(byte[] data)


/**
Verify a message signed by the Identos SDK.

@param signature64, signature for signed message
@param data, signed message
@return int, verification status
*/

public int verify(string signature64, byte[] data);

Errors

IDENTOS uses response codes to indicate sucess or failure of a request

Response Codes

public enum IdentosStatus {
Success = 0,
Failed = -1,
InvalidState = -2,
InvalidParameter = -29,
DeviceUnregistered = -50,
InvalidPin = -101,
WrongPin = -102,
NoInternetAccess = -200
}

Sample Program

using System;
using com.identos;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Runtime.Serialization;
using System.IO;
using System.Text;
using System.Collections.Generic;

namespace Test
{
class Program
{
// Application identifier, provided by Identos
private static String IdentosAppId = "dfd7b53b-33bd-48be-a05d-7dd10a85faaf";
private static String IdentosClientKey = "se6rm0ar75d0mnviroefdarcqn";
private static String IdentosAppVersion = "1.0.0";
/**
// Server Key, provided by Identos

NOTE: In practice, this key SHOULD NOT be included in the client
It is included here for easy of demostration purposes only

Instead, send the device package to YOUR server, authenticate the user, and only then register the device to Identos
*/
private static String IdentosServerKey = "gvahp2vrt6a111arpocpal2rog";

// Reference to the last input to encryption function
private static string plaintextHexWasEncrypted;
// Reference to the last encyrpted data, input to decrypt operation
private static string encryptedText;

public enum IdentosStatus
{
Success = 0,
Failed = -1,
InvalidState = -2,
InvalidParameter = -29,
DeviceUnregistered = -50,
InvalidPin = -101,
WrongPin = -102,
NoInternetAccess = -200
};

private static Dictionary<string, Identos> Users = new Dictionary<string, Identos>();
private static string CurrentUser;
private static string signedTextSignature;
private static byte [] bytesWasSigned;

static void Main(string[] args)
{

mainMenuLoop();

Console.WriteLine("End");
Console.ReadLine();
}

public static bool authenticateUser(Identos identos)
{
Console.WriteLine("Enter your passphrase: ");
string passphrase = Console.ReadLine();

/**
Authenticate the user by their passphase

The passphare will unlock their local private key and opens all other SDK functions for use\

@param passphrase The users passphase, the same one used at register

@return IdentosStatus
*/
IdentosStatus authStatus = (IdentosStatus)identos.authenticate(passphrase);
return (authStatus == IdentosStatus.Success);
}



/**
Display the menu until user quits
*/
public static void mainMenuLoop()
{
while (showMenu())
{
// pass
}
}


/**
Show the menu on the command line and execute the selected option

e Encrypt some random data
d Decrypt the result from the last encryption
g Grant a user access to an encryption key
q Quit

@return true to continue, false to stop
*/
public static bool showMenu()
{
Console.WriteLine();
Console.WriteLine("Identos");
if(CurrentUser != null)
{
Console.WriteLine("Welcome " + CurrentUser);

Console.WriteLine("e. Encrypt");
Console.WriteLine("d. Decrypt");
Console.WriteLine("g. Grant");
Console.WriteLine("c. Change User");
Console.WriteLine("s. Sign");
Console.WriteLine("v. Verify");
Console.WriteLine("q. Quit");

String input = Console.ReadLine();

if (input.Equals("e"))
{
encryptAction();
}
else if (input.Equals("d"))
{
decryptAction();
}
else if (input.Equals("g"))
{
grantAction();
}
else if (input.Equals("q"))
{
return false;
}
else if (input.Equals("c"))
{
changeUser();
}
else if (input.Equals("s"))
{
signAction();
}
else if (input.Equals("v"))
{
verifyAction();
}

return true;
}
else
{

changeUser();

return true;
}

}


public static void changeUser()
{

/*
* We will support multiple users by
*/
string username = getUsername();
// username = null;

Identos ctx;
if(Users.TryGetValue(username, out ctx))
{
CurrentUser = username;
return;
}

initalizeContext(username);
}

public static void initalizeContext(string username)
{
/**
Initialize the Identos SDK

This is always the first call you make to the SDK

@param appId - Your app id, provided by Identos
@param clientKey - Your client key, provided by Identos
@param version - Your app version, allows different security policies based on version
@param path – app directory, this is where identos generated files are kept

@return IdentosStatus

*/
Identos identos = Identos.Instance;
IdentosStatus initializeStatus = (IdentosStatus)identos.initialize(IdentosAppId, IdentosClientKey, IdentosAppVersion, false, username);
Console.WriteLine("Identos: initialize: " + initializeStatus);

// Depending on the status we will either register this device, or display the main menu
if (initializeStatus == IdentosStatus.Success)
{
// authenticate the user
if (authenticateUser(identos) == true)
{
// if authenticated, show main menu until quit
Console.WriteLine("Authenticate Success");
Users[username] = identos;
CurrentUser = username;

}
else
{
// failed to authenticate
Console.WriteLine("Authenticate Failed");
}
}
else if (initializeStatus == IdentosStatus.DeviceUnregistered)
{
// device unknown by Identos Server, register the device

registerDevice(username, identos);
initalizeContext(username);
}
else
{
// failure state

}
}

public static Identos currentContext()
{
if(CurrentUser == null) { return null; }
Identos ctx;
if (Users.TryGetValue(CurrentUser, out ctx)) { return ctx; }

return null;
}


public static void encryptAction()
{
// Generate Random Data to encrypt
byte[] bytes = new byte[128];
Random random = new Random();
random.NextBytes(bytes);

// Get the Key Identifier to encrypt under
Console.WriteLine("Enter an identifier (optional): ");
string identifier = Console.ReadLine();
if(String.IsNullOrEmpty(identifier))
{
identifier = null;
}

// Display the plaintext in hex format
string toEncryptAsHex = ByteArrayToString(bytes);
Console.WriteLine("To Encrypt Hex:");
Console.WriteLine(toEncryptAsHex);

/**
Encrypt a byte[]

@param bytes Data to encrypt
@param identifier Optional key identifier

@return identos_return_data
*/
identos_return_data ret = currentContext().encrypt(bytes, identifier);

// Log status of operation
IdentosStatus status = (IdentosStatus) ret.status;
Console.WriteLine();
Console.WriteLine("Status: " + status);

if (status == IdentosStatus.Success)
{
// save these values for decryption and comparioson of result
encryptedText = ret.data64; ;
plaintextHexWasEncrypted = toEncryptAsHex;

// display encrypted text
Console.WriteLine("Encrypted Text: ");
Console.WriteLine(encryptedText);
}

}

public static void decryptAction()
{
string cipher = encryptedText;

/**
Decrypt the result of a previous encryption (should be a based64 encoded string)

@param cipher Ciphertext

@return identos_return_data
*/
identos_return_data ret = currentContext().decrypt(cipher);

IdentosStatus status = (IdentosStatus)ret.status;

// Log status of operation
Console.WriteLine();
Console.WriteLine("Status: " + status);

if (status == IdentosStatus.Success)
{
// Displayed decryption result
byte[] unencodedResult = Base64Decode(ret.data64);
string decryptedAsHex = ByteArrayToString(unencodedResult);

Console.WriteLine("Decrypted Hex: ");
Console.WriteLine(decryptedAsHex);
Console.WriteLine("Key Identifier: " + ret.identifier);

//byte[] unencodedResult2 = Base64Decode(unencodedResult);
//string decryptedAsHex2 = ByteArrayToString(unencodedResult2);

//Console.WriteLine("Decrypted Hex: ");
//Console.WriteLine(decryptedAsHex2);

// Compare deciphered text to original plaintext
if (plaintextHexWasEncrypted != null && plaintextHexWasEncrypted.Equals(decryptedAsHex))
{
Console.WriteLine();
Console.WriteLine("-> Decrypted Text Equal To Original Plaintext");
}
}

}

public static void grantAction()
{
Console.WriteLine();

// The Identos user id to grant access to
Console.WriteLine("Grant User Id: ");
string uid = Console.ReadLine();

// the key identifier to grant access to
Console.WriteLine("To Identifier: ");
string identifier = Console.ReadLine();

/**
Grant a user access to an en/decryption key

@param identifier
@param uid

@return IdentosStatus
*/
IdentosStatus status = (IdentosStatus)currentContext().grant(identifier, uid);

// Log the result
if (status == IdentosStatus.Success)
{
Console.WriteLine("Granted " + uid + " access to " + identifier);
}
else
{
Console.WriteLine("Error granting " + uid + " access to " + identifier);
}

}


private static void verifyAction()
{
if (String.IsNullOrEmpty(signedTextSignature) ||
(bytesWasSigned == null))
{
Console.WriteLine("Nothing to verify");
return;
}

int status = currentContext().verify(signedTextSignature, bytesWasSigned);
Console.WriteLine("Verification " + ((IdentosStatus)status == IdentosStatus.Success ? "passed" : "failed"));

}

private static void signAction()
{
// Generate Random Data to encrypt
byte[] bytes = new byte[128];
Random random = new Random();
random.NextBytes(bytes);

string toSignAsHex = ByteArrayToString(bytes);
Console.WriteLine("Message to Sign:");
Console.WriteLine(toSignAsHex);

//sign
identos_return_data returnData = currentContext().sign(bytes);

IdentosStatus status = (IdentosStatus)returnData.status;
Console.WriteLine();
Console.WriteLine("Status: " + status);

if (status == IdentosStatus.Success)
{
// save these values for decryption and comparison of result
signedTextSignature = returnData.data64; ;
bytesWasSigned = bytes;

// display encrypted text
Console.WriteLine("Signature: ");
Console.WriteLine(signedTextSignature);
}
}


public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}

public static byte[] Base64Decode(string base64EncodedData)
{
return System.Convert.FromBase64String(base64EncodedData);
}

public static string getUsername()
{
Console.WriteLine("Enter your username: ");
string username = Console.ReadLine();
return username;
}

public static string registerDevice(string username, Identos identos)
{


Console.WriteLine("Enter your passphrase: ");
string passphrase = Console.ReadLine();
/**
Authenticate with Identos.

If the device is is unregistered, Identos will create a temporary user.
The app can then query for the registration token from Identos.

@param pin - The PIN used during the device registration

@return authentication status
*/
IdentosStatus authStatus = (IdentosStatus)identos.authenticate(passphrase);

Console.WriteLine("Authentication result: " + authStatus);
/**
Get registration token from Identos.

@return registration_token
*/

string registration_token = identos.registration_token();
Console.WriteLine("Registration token: " + registration_token);

/**
As the backend, register the user to Identos Server. For demonstration purposes,
this app will also act as the backend.

@param appId - Your app id, provided by Identos
@param clientKey - Your client key, provided by Identos
@param registration_token - token given by Identos after device successfuly authenticates
@param username

@return userId
*/
string userId = registerUser(IdentosAppId, IdentosServerKey, registration_token, username);
Console.WriteLine("User ID: " + userId);
return userId;
}


public static string registerUser(string appId, string serverKey, string registration_token, string username)
{
string requestJson = new RegisterUserRequest
{
appid = appId,
serverkey = serverKey,
username = username,
deviceToken = registration_token
}.ToJson();

using (var webClient = new WebClient())
{
webClient.Headers.Add(HttpRequestHeader.ContentType, "application/json");
string responseJson = webClient.UploadString("https://sandbox.identos.ca/api/v1/user/register", requestJson);
var response = RegisterUserResponse.FromJson(responseJson);
return response.userid;
}
}



}
[DataContract]
public class RegisterUserRequest
{
[DataMember]
public string appid;
[DataMember]
public string serverkey;
[DataMember]
public string username;
[DataMember(Name = "device-token")]
public string deviceToken;

public string ToJson()
{
var serializer = new DataContractJsonSerializer(typeof(RegisterUserRequest));
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, this);
ms.Position = 0;
using (var sr = new StreamReader(ms))
{
string json = sr.ReadToEnd();
return json;
}
}
}
}
[DataContract]
public class RegisterUserResponse
{
[DataMember]
public string userid;

public static RegisterUserResponse FromJson(string json)
{
var serializer = new DataContractJsonSerializer(typeof(RegisterUserResponse));
var ms = new MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(json));

RegisterUserResponse registerUserResponse = (RegisterUserResponse)serializer.ReadObject(ms);
return registerUserResponse;
}
}
}