FTN13: FutoIn Secure Vault Version: 0.DV2 Date: 2018-01-15 Copyright: 2014-2018 FutoIn Project (http://futoin.org) Authors: Andrey Galkin
It is not a new concept, but standardization of higher level interface for Host Security Modules and similar pure software or hardware components.
The main idea is that critical sensitive data is accessible only to a small peace of software/hardware effectively limiting scope of source code, hardware design and/or infrastructure required to be audited for security issues in first place. Most flaws in other software parts of larger project should have less impact on sensitive data disclosure.
Critical sensitive data: private or shared cryptography secrets, keys for tokenization of data, etc.
Secure Vault (SV) is assumed to be a FutoIn service with the following characteristics:
The following features are required:
Each implementation may choose to support any subset of all availables types.
The specifications tries to cover only commonly used algorithms, but actual implementation may add custom constants.
Specification intentionally does not list specific types to be as generic as possible.
Suggested list, self-explanatory:
RSA
EdDSA
GOST3410
- GOST 34.10 PKIversion
- string:paramset
- set:AES-CBC
AES-CTR
AES-GCM
GOST3412-CBC
GOST3412-CTR
GOST3412-CFB
GOST3410
RSA
HKDF
PBKDF2
SV must obey key constraints:
encrypt
- allow encryption and decryptionsign
- allow signing and verificationderive
- allow key derivingshared
- allow key to be exposed externallytemp
- allow auto-purge after common configured time-to-liveSV must collect key usage statistics as a hint to regenerate keys and/or block possible attacks.
Any key is created for some purpose. So, external ID is mandatory and can be used implementation-defined way to recover from errors like timeouts without unused key artifacts hanging in SV.
Initialization Vector (IV) is required for most cases of data encryption. There is known flexibility with padding strategy. Authentication tag passing is required for authenticated data decryption.
As it's very easy to mess up and this spec also definitely has some flaws, the spec tries to minimize user's decision making on encryption.
General strategy:
MessageSignature
constraint.Implementation should use the following defaults for key transport representation.
{
"iface" : "futoin.secvault.types",
"version" : "{ver}",
"ftn3rev" : "1.9",
"imports" : [
"futoin.types:1.0"
],
"types" : {
"KeyID" : "UUIDB64",
"ExtID" : {
"type" : "string",
"minlen" : 1,
"maxlen" : 128
},
"KeyType" : {
"type" : "GenericIdentifier",
"minlen" : 1,
"maxlen" : 32
},
"KeyUsage" : {
"type" : "set",
"items" : [
"encrypt",
"sign",
"derive",
"shared",
"temp"
]
},
"GenParams" : [
"string",
"integer",
"map"
],
"KeyInfo" : {
"type" : "map",
"fields" : {
"id" : "KeyID",
"ext_id" : "ExtID",
"usage" : "KeyUsage",
"type" : "KeyType",
"params" : "GenParams",
"created" : "Timestamp",
"used_times" : "NotNegativeInteger",
"used_bytes" : "NotNegativeInteger",
"sig_failures" : "NotNegativeInteger"
}
},
"KeyIDList" : {
"type" : "array",
"elemtype" : "KeyID"
},
"RawData" : {
"type" : "data",
"maxlen" : 1048576
},
"KeyData" : {
"type" : "data",
"maxlen" : 16384
},
"PublicKeyData" : {
"type" : "data",
"maxlen" : 16384
},
"PublicKey" : {
"type" : "map",
"fields": {
"key_type" : "KeyType",
"data" : "PublicKeyData"
}
},
"HashType" : {
"type" : "string",
"regex" : "^[a-Z0-9][a-Z0-9-]*[a-Z0-9]$",
"maxlen" : 16
},
"CipherMode" : {
"type" : "enum",
"items" : [
"CBC",
"CTR",
"GCM",
"CFB"
]
},
"KeyDerivationFunction" : "KeyType",
"InitializationVector" : {
"type" : "data",
"maxlen" : 128,
"desc" : "Most ciphers accept only block size, e.g. 16 bytes"
}
},
"requires" : [
"SecureChannel",
"BinaryData"
]
}
{
"iface" : "futoin.secvault.keys",
"version" : "{ver}",
"ftn3rev" : "1.9",
"imports" : [
"futoin.secvault.types:{ver}"
],
"funcs" : {
"unlock" : {
"params" : {
"secret" : "KeyData"
},
"result" : "boolean",
"throws" : [
"InvalidSecret"
]
},
"lock" : {
"result" : "boolean"
},
"generateKey" : {
"params" : {
"ext_id" : "ExtID",
"usage" : "KeyUsage",
"key_type" : "KeyType",
"gen_params" : "GenParams"
},
"result" : "KeyID",
"throws" : [
"UnsupportedType",
"OrigMismatch"
]
},
"injectKey" : {
"params" : {
"ext_id" : "ExtID",
"usage" : "KeyUsage",
"key_type" : "KeyType",
"gen_params" : "GenParams",
"data" : "KeyData"
},
"result" : "KeyID",
"throws" : [
"UnsupportedType",
"OrigMismatch",
"InvalidKey"
]
},
"injectEncryptedKey" : {
"params" : {
"ext_id" : "ExtID",
"usage" : "KeyUsage",
"key_type" : "KeyType",
"gen_params" : "GenParams",
"data" : "KeyData",
"enc_key" : "KeyID",
"mode" : "CipherMode"
},
"result" : "KeyID",
"throws" : [
"UnsupportedType",
"OrigMismatch",
"UnknownKeyID",
"NotApplicable",
"InvalidKey"
]
},
"deriveKey" : {
"params" : {
"ext_id" : "ExtID",
"usage" : "KeyUsage",
"key_type" : "KeyType",
"gen_params" : "GenParams",
"base_key" : "KeyID",
"kdf" : "KeyDerivationFunction",
"hash" : "HashType",
"salt" : "KeyData",
"other" : "map"
},
"result" : "KeyData",
"throws" : [
"UnknownKeyID",
"UnsupportedKey",
"UnsupportedDerivation",
"InvalidParams",
"NotApplicable"
]
},
"wipeKey" : {
"params" : {
"id" : "KeyID"
},
"result" : "boolean"
},
"exposeKey" : {
"params" : {
"id" : "KeyID"
},
"result" : "KeyData",
"throws" : [
"UnknownKeyID",
"NotApplicable"
]
},
"encryptedKey" : {
"params" : {
"id" : "KeyID",
"enc_key" : "KeyID",
"mode" : "CipherMode"
},
"result" : "KeyData",
"throws" : [
"UnknownKeyID",
"NotApplicable"
]
},
"pubEncryptedKey" : {
"params" : {
"id" : "KeyID",
"pubkey" : "PublicKey",
"key_type" : "KeyType"
},
"result" : "KeyData",
"throws" : [
"UnknownKeyID",
"NotApplicable"
]
},
"publicKey" : {
"params" : {
"id" : "KeyID"
},
"result" : "KeyData",
"throws" : [
"UnknownKeyID",
"NotApplicable"
]
},
"keyInfo" : {
"params" : {
"id" : "KeyID"
},
"result" : "KeyInfo",
"throws" : [
"UnknownKeyID"
]
},
"listKeys" : {
"result" : "KeyIDList"
}
},
"requires" : [
"SecureChannel",
"BinaryData"
]
}
{
"iface" : "futoin.secvault.data",
"version" : "{ver}",
"ftn3rev" : "1.9",
"imports" : [
"futoin.secvault.types:{ver}"
],
"funcs" : {
"encrypt" : {
"params" : {
"id" : "KeyID",
"data" : "RawData",
"mode" : "CipherMode",
"iv" : {
"type" : "InitializationVector",
"default" : null
},
"aad" : {
"type" : "RawData",
"default" : null
}
},
"result" : "RawData",
"throws" : [
"UnsupportedType",
"UnsupportedCipher",
"NotApplicable"
],
"maxreqsize" : "1100K",
"maxrspsize" : "1100K"
},
"decrypt" : {
"params" : {
"id" : "KeyID",
"data" : "RawData",
"mode" : "CipherMode",
"aad" : {
"type" : "RawData",
"default" : null
}
},
"result" : "RawData",
"throws" : [
"UnsupportedType",
"UnsupportedCipher",
"InvalidData",
"NotApplicable"
],
"maxreqsize" : "1100K",
"maxrspsize" : "1100K"
},
"sign" : {
"params" : {
"id" : "KeyID",
"data" : "RawData",
"hash" : "HashType"
},
"result" : "RawData",
"throws" : [
"UnsupportedType",
"UnsupportedHash",
"InvalidData",
"NotApplicable"
],
"maxreqsize" : "1100K"
},
"verify" : {
"params" : {
"id" : "KeyID",
"data" : "RawData",
"sig" : "RawData",
"hash" : "HashType"
},
"result" : "boolean",
"throws" : [
"UnsupportedType",
"UnsupportedHash",
"InvalidData",
"InvalidSignature",
"NotApplicable"
],
"maxreqsize" : "1100K"
}
},
"requires" : [
"SecureChannel",
"BinaryData"
]
}
=END OF SPEC=