Sleds/libeye/eyering.h

715 lines
25 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) 2013-2015 IONU Security, Inc. All rights reserved.
//
// Keyring and Key classes for secure storage and management of keys
#ifndef eyering_h
#define eyering_h
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <openssl/evp.h>
#include "eyeconstants.h"
#include "eyejson.h"
#include "eyeencrypteddb.h"
#ifndef LIBEYE_DLL
#ifdef WIN32
# ifdef DLLEXPORT
# define LIBEYE_DLL __declspec(dllexport)
# else
# define LIBEYE_DLL __declspec(dllimport)
# endif
#else
#define LIBEYE_DLL
#endif
#endif
namespace sequencelogic {
#define SL_KEYRING_DIGEST_LEN 20 // sha1
#define SL_ECDH_HMAC_LEN 32 // sha256
#define SL_ECDH_SECRET_LEN 64 // sha512
class Key {
friend class Keyring;
public:
enum KEY_TYPE {
RSA,
RSA_PUBLIC,
AES,
EC,
EC_PUBLIC,
STRING,
AESHMAC,
GENERIC
};
enum KEY_FORMAT {
PEM,
DER,
PKCS8,
PKCS12,
UNKNOWN_FORMAT
};
/**
* @constructor
* @param name of the key
* @param description of the key
* @param length of the key
* @param key bytes
* @param type of the key
*/
LIBEYE_DLL Key (const std::string& name, const std::string& desc, size_t len, const unsigned char* key, KEY_TYPE type);
/**
* @constructor
* @param name of the key
* @param description of the key
* @param key bytes
* @param type of the key
*/
LIBEYE_DLL Key (const std::string& name, const std::string& desc, const std::string& key, KEY_TYPE type);
/**
* @constructor
* @param name of the key
* @param description of the key
* @param filename of key (PEM or DER format)
* @param password or "" if not protected by PKCS#8
*/
LIBEYE_DLL Key (const std::string& name, const std::string& desc, const std::string& filename, const std::string& password);
/**
* @constructor
* @param filename of key (PEM or DER format)
* @param password or "" if not protected by PKCS#8
*/
LIBEYE_DLL Key (const std::string& filename, const std::string& password);
/**
* @constructor
*/
LIBEYE_DLL Key();
/**
* @destructor
*/
LIBEYE_DLL ~Key();
/**
* Check if the key is valid
* @return true or false
*/
LIBEYE_DLL bool IsValid() const;
/**
* AES-CBC encrypt with 128 or 256 bit key
* @param input plaintext
* @param input length
* @param output length
* @param initial value (16 bytes)
* @return ciphertext or nullptr
*/
LIBEYE_DLL unsigned char* SymmetricDecryptBuffer (const unsigned char* in, size_t inlen, size_t* outlen,
const unsigned char* iv) const;
/**
* AES-CBC decrypt with 128 or 256 bit key
* @param input ciphertext
* @param input length
* @param output length
* @param initial value (16 bytes)
* @return plaintext or nullptr
*/
LIBEYE_DLL unsigned char* SymmetricEncryptBuffer (const unsigned char* in, size_t inlen, size_t* outlen,
const unsigned char* iv) const;
/**
* AES-CBC encrypt file with 128 or 256 bit key
* @param plaintext filename
* @param encrypted filename
* @param initial value (16 bytes)
* @return true for success
*/
LIBEYE_DLL bool SymmetricEncryptFile (const std::string& plainfile, const std::string& encryptedfile,
const unsigned char* iv) const;
/**
* AES-CBC decrypt file with 128 or 256 bit key
* @param encrypted filename
* @param plaintext filename
* @param initial value (16 bytes)
* @return true for success
*/
LIBEYE_DLL bool SymmetricDecryptFile (const std::string& encryptedfile, const std::string& plainfile,
const unsigned char* iv) const;
/**
* AES-GCM encrypt with 256 bit key, authenticated with optional additional authenticated data
* @param input plaintext
* @param input length
* @param output length
* @param initial value (16 bytes)
* @param additional authenticated data
* @param length of additional authenticated data
* @return ciphertext or nullptr
*/
LIBEYE_DLL unsigned char* SymmetricEncryptAuthenticated (const unsigned char *plaintext, size_t inlen, size_t* outlen,
const unsigned char *iv,
const unsigned char *aad = nullptr, size_t aadlen = 0) const;
/**
* AES-GCM decrypt with 256 bit key, authenticated with optional additional authenticated data
* @param input ciphertext
* @param input length
* @param output length
* @param initial value (16 bytes)
* @param additional authenticated data
* @param length of additional authenticated data
* @return plaintext or nullptr
*/
LIBEYE_DLL unsigned char* SymmetricDecryptAuthenticated (const unsigned char *ciphertext, size_t inlen, size_t* outlen,
const unsigned char *iv,
const unsigned char *aad = nullptr, size_t aadlen = 0) const;
/**
* AES-CBC encrypt with 256 bit key and keyed HMAC for authentication
* @param input plaintext
* @param input length
* @param output length
* @return ciphertext or nullptr
*/
LIBEYE_DLL unsigned char* HMACEncrypt (const unsigned char* in, size_t inlen, size_t* outlen) const;
/**
* AES-CBC decrypt with 256 bit key and keyed HMAC for authentication
* @param input ciphertext
* @param input length
* @param output length
* @return plaintext
*/
LIBEYE_DLL unsigned char* HMACDecrypt (const unsigned char* in, size_t inlen, size_t* outlen) const;
/**
* RSA encryption, plaintext length is 214 byte maximum with EME-OAEP padding
* @param input plaintext
* @param input length
* @param output length
* @return ciphertext or nullptr
*/
LIBEYE_DLL unsigned char* PublicKeyEncrypt (const unsigned char* in, size_t inlen, size_t* outlen) const;
/**
* RSA decryption
* @param input ciphertext
* @param input length
* @param output length
* @return plaintext or nullptr
*/
LIBEYE_DLL unsigned char* PrivateKeyDecrypt (const unsigned char* in, size_t inlen, size_t* outlen) const;
/**
* RSA sign
* @param input to be signed
* @param input length
* @param signature length
* @return signature or nullptr
*/
LIBEYE_DLL unsigned char* PrivateKeySign (const unsigned char* tbs, size_t tbslen, size_t* siglen) const;
/**
* RSA verify
* @parameter signature to verify
* @param signature length
* @param input to be signed
* @param input length
* @return 0 for success, non-zero for failure
*/
LIBEYE_DLL int PublicKeyVerify (const unsigned char* sig, size_t siglen, const unsigned char* tbs, size_t tbslen) const;
// These are unsecure and misnamed, provided for compatibility with the libionu version for CG token exchange
LIBEYE_DLL unsigned char* RSAPrivateKeyEncrypt (const unsigned char* in, size_t inlen, size_t* outlen) const;
LIBEYE_DLL unsigned char* RSAPublicKeyDecrypt (const unsigned char* in, size_t inlen, size_t* outlen) const;
/**
* ECIES based encryption, uses ephemeral EC key
* @param input plaintext
* @param input length
* @param output length
* @return ciphertext or nullptr
*/
LIBEYE_DLL unsigned char* ECIESEncrypt (const unsigned char* in, size_t inlen, size_t* outlen) const;
/**
* ECIES based decryption, uses ephemeral EC key
* @param input ciphertext
* @param input length
* @param output length
* @return plaintext or nullptr
*/
LIBEYE_DLL unsigned char* ECIESDecrypt (const unsigned char* in, size_t inlen, size_t* outlen) const;
/**
* RSA IES based encryption, uses ephemeral AES key to extend size
* @param input plaintext
* @param input length
* @param output length
* @return ciphertext or nullptr
*/
LIBEYE_DLL unsigned char* RSAIESEncrypt (const unsigned char* in, size_t inlen, size_t* outlen) const;
/**
* RSA IES based decryption, uses ephemeral AES key to extend size
* @param input ciphertext
* @param input length
* @param output length
* @return plaintext or nullptr
*/
LIBEYE_DLL unsigned char* RSAIESDecrypt (const unsigned char* in, size_t inlen, size_t* outlen) const;
// Generate ECDH shared secret with peer's public key
LIBEYE_DLL unsigned char* ECDHEncrypt (const Key* peer, const unsigned char* in, size_t inlen, size_t* outlen) const;
LIBEYE_DLL unsigned char* ECDHDecrypt (const Key* peer, const unsigned char* in, size_t inlen, size_t* outlen) const;
LIBEYE_DLL unsigned char* GenerateECDHSecret (const Key* peer, size_t* secret_len) const;
/**
* Get PEM format public key for RSA or EC private key
* @return PEM formatted public key or nullptr
*/
LIBEYE_DLL char* GetPubKey() const;
/**
* Get the public key fingerprint (e.g. '38:52:77:78:11:24:e6:8b:33:ea:37:1c:9a:10:f3:1d:5d:dc:d4:5d')
* @return fingerprint
*/
LIBEYE_DLL std::string PublicKeyFingerPrint () const;
/**
* Export to PEM or DER format as determined by extension
* @param filename of key (PEM or DER format)
* @param password or "" if not protected by PKCS#8
* @return true for success
*/
LIBEYE_DLL bool Export (const std::string& filename, const std::string& password) const;
/**
* Import key from file
* @param filename of key (PEM or DER format)
* @param password or "" if not protected by PKCS#8
* @return true for success
*/
LIBEYE_DLL bool Import (const std::string& filename, const std::string& password);
/**
* Import key from buffer
* @param buffer containing key data
* @param length of buffer
* @param password or "" if not protected by PKCS#8
* @param format of key (PEM or DER)
* @return true for success
*/
LIBEYE_DLL bool Import (const char* buffer, size_t bytes, const std::string& password, KEY_FORMAT format);
// Duplicate a key, rekey
void Duplicate (const Key* dupkey);
void SetType (KEY_TYPE type) {_type = type; }
void SetKey (const unsigned char* key, size_t bytes);
void SetIv (const unsigned char* iv, size_t bytes);
const std::string GetName() const { return _name; }
const std::string GetDescription() const { return _desc; }
size_t GetLength() const { return _len; }
LIBEYE_DLL const unsigned char* GetKey() const { return _key; }
const unsigned char* GetIv() const { return _iv; }
KEY_TYPE GetType() const { return _type; }
LIBEYE_DLL const std::string GetStringKey() const;
LIBEYE_DLL bool Equals (const Key& other) const;
LIBEYE_DLL void Dump() const;
private:
KEY_TYPE _type; // Key type - RSA, AES, TGI, STRING, GENERIC
std::string _name; // Name of the key
std::string _desc; // Descriptive text [optional]
size_t _len; // Length of key in bytes
unsigned char* _key; // Actual key data
unsigned char* _iv; // Initial value or nonce, may or may not be present and is not saved
unsigned char _obf; // Random obfuscation byte
unsigned char* HMACCrypt (bool encrypt, const unsigned char* in, size_t inlen, size_t* outlen) const;
unsigned char* PublicKeyCrypt (bool encrypt, const unsigned char* in, size_t inlen, size_t* outlen) const;
unsigned char* RSAKeyCrypt (bool encrypt, const unsigned char* in, size_t inlen, size_t* outlen) const;
unsigned char* ECDHKeyCrypt (const Key* peer, bool encrypt, const unsigned char* in, size_t inlen, size_t* outlen) const;
// From the file extension determine the format to read/write
KEY_FORMAT GetKeyFormat (const std::string& filename) const;
std::string GetKeyTypeStr() const;
// Encrypt/Decrypt the key
void Encrypt (EVP_CIPHER_CTX* ctx, const unsigned char* key, const unsigned char* iv);
void Decrypt (EVP_CIPHER_CTX* ctx, const unsigned char* key, const unsigned char* iv);
// Get the value parameters as a json string, load from JSON
std::string GetValueJSON() const;
bool LoadValueJSON (const std::string& name, const std::string& json);
EyeJSONObject* GetJSONObject() const;
std::string ToJSON () const;
};
// Keyring holds any number of keys and linked keyrings
// It is always encrypted on disk, and until unlocked also in memory
class Keyring {
public:
enum RING_STATUS {
VALID,
INVALID, // Not a valid keyring, can't open file
CORRUPT // keyring is corrupt
};
/**
* Keyring constructor
* @param name of the keyring
* @param filename of the SQLite database file
* @param key to lock/unlock the keyring
*/
LIBEYE_DLL Keyring (const std::string& name, const std::string& database, const Key& key);
/**
* Keyring constructor
* @param name of the keyring
* @param filename of the SQLite database file
* @param password to lock/unlock the keyring
*/
LIBEYE_DLL Keyring (const std::string& name, const std::string& database, const std::string& password);
/**
* Keyring constructor
* @param name of the keyring
* @param description of the keyring
*/
LIBEYE_DLL Keyring (const char* name, const char* desc);
/**
* Keyring constructor
* @param filename for the keyring
*/
LIBEYE_DLL Keyring (const char* filename);
/**
* Keyring destructor
*/
LIBEYE_DLL ~Keyring();
LIBEYE_DLL bool IsLocked () { return _isLocked; }
LIBEYE_DLL RING_STATUS GetStatus () { return _status; }
/**
* Lock the keyring with a password
* @param password
* @return true for success
*/
LIBEYE_DLL bool Lock (const char* password);
/**
* Unlock the keyring with a password
* @param password
* @return true for success
*/
LIBEYE_DLL bool Unlock (const char* password);
/**
* Lock the keyring with a 256 bit AES key
* @param key to lock keyring
* @return true for success
*/
LIBEYE_DLL bool Lock (const unsigned char* key);
/**
* Unlock the keyring with a 256 bit AES key
* @param key to unlock keyring
* @return true for success
*/
LIBEYE_DLL bool Unlock (const unsigned char* key);
/**
* Save the keyring to disk
* @return true for success
*/
LIBEYE_DLL bool Save ();
/**
* Save the keyring to disk
* @param filename
* @return true for success
*/
LIBEYE_DLL bool SaveAs (const char* filename);
/**
* Add key to keyring, replaces existing key of same name
* @param key to add
* @return true for success
*/
LIBEYE_DLL bool AddKey (Key* key);
/**
* Add key to keyring, replaces existing key of same name
* @param name of the key
* @param description of the key
* @param length of the key
* @param key bytes
* @param type of the key
*/
LIBEYE_DLL bool AddKey (const std::string& name, const std::string& desc, size_t len, const unsigned char* key, Key::KEY_TYPE type);
/**
* Get key from keyring
* @param name of the key
* @return key or nullptr if not found
*/
LIBEYE_DLL const Key* GetKey (const std::string& keyname) const;
/**
* Get key from keyring
* @param name of the key
* @param key to fill in
* @return true if found
*/
LIBEYE_DLL bool GetKey (const std::string& name, Key& key) const;
/**
* Get public key from keyring
* @param name of the key
* @return true if found and RSA or EC key
*/
LIBEYE_DLL char* GetPubKey (const char* keyname);
/**
* Remove key from keyring
* @param name of the key
* @return true if removed
*/
LIBEYE_DLL bool RemoveKey (const std::string& keyname);
/**
* Update key in keyring
* @param name of the key
* @return true if updated
*/
LIBEYE_DLL bool UpdateKey (const Key* key);
/**
* Generate a random 2048 bit RSA keypair and add private key to keyring
* @param name of the key
* @param description of the key
* @return true for success
*/
LIBEYE_DLL bool GenerateRSAKey (const char* name, const char* desc);
/**
* Generate a random 256 bit AES key and add to keyring
* @param name of the key
* @param description of the key
* @return true for success
*/
LIBEYE_DLL bool GenerateAESKey (const char* name, const char* desc);
/**
* Generate a random 256 bit AES plus 256 bit HMAC key and add to keyring
* @param name of the key
* @param description of the key
* @return true for success
*/
LIBEYE_DLL bool GenerateAESHMACKey (const char* name, const char* desc);
/**
* Generate random 521 bit EC key using ANSI X9.62 Prime 521 curve and add to the keyring
* @param name of the key
* @param description of the key
* @return true for success
*/
LIBEYE_DLL bool GenerateECKey (const char* name, const char* desc);
/**
* Import the public key from PEM encoded X509 certificate
* @param filename for certificate
* @return true for success
*/
LIBEYE_DLL bool ImportPubKeyFromCert (const std::string& filename);
/**
* Generate 2048 RSA keypair using a secret string to seed a DBRG, such that
* given same secret will produce the same key, and add the private key to keyring
* @param name of the key
* @param description of the key
* @param seed for DRBG
* @return true for success
*/
LIBEYE_DLL bool GenerateRSAKey (const std::string& keyname, const std::string& desc, const std::string& seed);
/**
* Provision a challenge based account key pair
* @param keyname name of the key to be added to keyring
* @param challenges challenge answer set
* @param salt empty for initial provision, cgsalt for subsequent
* @return salt - base64 encoded salt
*/
LIBEYE_DLL bool ProvisionChallengeRSAKey (const std::string& keyname, const std::string& challenges, std::string& salt);
/**
* Provision an account code based key pair
* @param keyname name of the key to be added to keyring
* @param code account/recovery code, may be empty for initial provision
* @param salt empty for initial provision, cgsalt for subsequent
* @param challenges new challenge answer set
* @return code,salt - code,base64 encoded salt
*/
LIBEYE_DLL bool ProvisionAccountRSAKey (const std::string& keyname, std::string& code, std::string& salt, const std::string& challenges);
/**
* Generate deterministic 2048 bit RSA keypair, add private key to keyring
* - old style challenge only, call with challenges: secret and salt == ""
* - new style pre-provision only, call with secret: challenges and salt == ""
* - provision and get salt, call with challenges and secret
* - new style salted seed, call with challenges and salt: secret == ""
* - recovery/provision, call with secret and salt
* @param name of the key
* @param description of the key
* @param challenge answer string
* @param secret provision/recovery code, input and output
* @param salt as hex, base64 or byte string
* @return true for success
*/
LIBEYE_DLL bool GenerateRSAKey (const std::string& name, const std::string& desc, const std::string& challenges, const std::string& secret, std::string& salt);
/**
* Generate 521 bit EC keypair using a json challenge string to seed a DBRG, such that
* given same challenges will produce the same key, and add the private key to keyring
* @param name of the key
* @param description of the key
* @param challenge answer string to seed DRBG
* @return true for success
*/
LIBEYE_DLL bool GenerateECKey (const char* name, const char* desc, const char* challenges);
/**
* Generate deterministic 521 bit EC keypair, add private key to keyring
* - old style challenge only, call with challenges: secret and salt == ""
* - new style pre-provision only, call with secret: challenges and salt == ""
* - provision and get salt, call with challenges and secret
* - new style salted seed, call with challenges and salt: secret == ""
* @param name of the key
* @param description of the key
* @param challenge answer string
* @param secret string
* @param salt as hex, base64 or byte string
* @return true for success
*/
LIBEYE_DLL bool GenerateECKey (const std::string& name, const std::string& desc, const std::string& challenges, const std::string& secret, std::string& salt);
/**
* Pre-provision a set of keys from a van and list of email addresses, keyname=email, desc=secret
* @param domain string, van, company name...
* @param list of users to create keys for, could be email, username...
* @return true for success
*/
LIBEYE_DLL bool GenerateRSAKeys (const std::string& van, const std::vector<std::string>& emailist);
/**
* Encrypt plaintext using specifed key (can be AES, AESHMAC, EC, RSA)
* @param key to use for encryption
* @param input plaintext
* @param input length
* @param output length
* @param initialization vector
* @return ciphertext or nullptr
*/
LIBEYE_DLL unsigned char* Encrypt (const std::string keyname, const unsigned char *plaintext,
size_t inlen, size_t* outlen, const unsigned char *iv = nullptr) const;
/**
* Decrypt ciphertext using specifed key (can be AES, AESHMAC, EC, RSA)
* @param key to use for encryption
* @param input ciphertext
* @param input length
* @param output length
* @param initialization vector
* @return plaintext or nullptr
*/
LIBEYE_DLL unsigned char* Decrypt (const std::string keyname, const unsigned char *ciphertext,
size_t inlen, size_t* outlen, const unsigned char *iv = nullptr) const;
/**
* Add keyring and transfer ownership
* @param keyring to add
* @return true for success
*/
LIBEYE_DLL bool AddKeyring (Keyring* keyring);
/**
* Remove and delete keyring
* @param keyring to remove
* @return true for success
*/
LIBEYE_DLL bool RemoveKeyring (const char* ringname);
/**
* Get the named keyring
* @param keyring to get
* @return keyring or nullptr
*/
LIBEYE_DLL const Keyring* GetKeyring (const char* ringname) const;
/**
* Load a keyring from JSON, deletes any exisiting keys
* @param json string to load keyring with
* @return true for success
*/
LIBEYE_DLL bool LoadFromJSON (const std::string& json);
/**
* Get key names
* @return JSON array of key names
*/
LIBEYE_DLL std::string GetKeyNames();
/**
* Convert the format to JSON string
* @param key to lock keyring
* @return JSON string representation of Keyring
*/
LIBEYE_DLL std::string Stringify (const Key& key);
LIBEYE_DLL void Dump();
const char* GetName() { return _name.c_str(); }
const char* GetDescription() { return _desc.c_str(); }
size_t GetNumKeys() { return _keys.size(); }
size_t GetNumRings() { return _keyrings.size(); }
private:
RING_STATUS _status; // Status of keyring
char* _filename; // Current filename
EyeEncryptedDB* _db; // Database (if used)
std::string _version; // Version of this key ring
bool _isLocked; // Has the Keyring been unlocked
bool _sync; // Should this keyring be sync'd
unsigned char _attempts; // Number of attempts to unlock
std::string _name; // Name of the keyring
std::string _desc; // Descriptive text [optional]
unsigned char _iv[SL_AES_BLOCK_LEN]; // Initialization vector
unsigned char _digest[SL_KEYRING_DIGEST_LEN]; // Message digest of key data
std::vector<Key*> _keys; // Array of keys
std::vector<Keyring*> _keyrings; // Array of linked keyrings
EVP_CIPHER_CTX _ctx; // Encryption context
static int GetRounds (const char* password);
bool DigestKeys (unsigned char* md_value);
EyeJSONObject* GetJSONObject() const;
EyeJSONObject* GetJSONObject (const Key& key);
bool AddJSONKeyring (EyeJSONObject* jring);
bool AddJSONKey (EyeJSONObject* jkey);
};
} //namespce ionu
#endif