module dicrpkid;
extern (Windows):
/* GENERAL FUNCTIONS */
int PKI_Version(void *reserved1, void *reserved2);
int PKI_LicenceType(int reserved);
int PKI_LastError(char *szErrMsg, int nMsgLen);
int PKI_ErrorCode();
int PKI_ErrorLookup(char *szErrMsg, int nMsgLen, int nErrCode);
int PKI_CompileTime(char *szTimestamp, int nLen);
int PKI_ModuleName(char *szTimestamp, int nLen, int reserved);
int PKI_PowerUpTests(int nOptions);
/* RFC3369 CRYPTOGRAPHIC MESSAGE SYNTAX FUNCTIONS */
int CMS_MakeEnvData(char *szFileOut, char *szFileIn, char *szCertList, char *sSeed, int nSeedLen, int nOptions);
int CMS_MakeEnvDataFromString(char *szFileOut, char *szDataIn, char *szCertList, char *sSeed, int nSeedLen, int nOptions);
int CMS_ReadEnvData(char *szFileOut, char *szFileIn, char *szX509File, char *szRSAPrivateKey, int nOptions);
int CMS_ReadEnvDataToString(char *szDataOut, int nDataOutLen, char *szFileIn, char *szX509File, char *szRSAPrivateKey, int nOptions);
int CMS_MakeSigData(char *szFileOut, char *szFileIn, char *szCertList, char *szRSAPrivateKey, int nOptions);
int CMS_MakeSigDataFromString(char *szFileOut, char *szDataIn, char *szCertList, char *szRSAPrivateKey, int nOptions);
int CMS_MakeDetachedSig(char *szFileOut, char *szHexDigest, char *szCertList, char *szRSAPrivateKey, int nOptions);
int CMS_ReadSigData(char *szFileOut, char *szFileIn, int nOptions);
int CMS_ReadSigDataToString(char *szDataOut, int nDataOutLen, char *szFileIn, int nOptions);
int CMS_GetSigDataDigest(char *szHexDigestOut, int nDigestLen, char *szFileIn, char *szX509File, int nOptions);
int CMS_VerifySigData(char *szFileIn, char *szX509File, char *szHexDigest, int nOptions);
int CMS_QuerySigData(char *szDataOut, int nDataOutLen, char *szFileIn, char *szQuery, int nOptions);
int CMS_MakeSigDataFromSigValue(char *szFileOut, ubyte *pSigValue, int nSigLen, ubyte *pData, int nDataLen, char *szCertList, int nOptions);
/* RSA KEY FUNCTIONS */
int RSA_MakeKeys(char *szPubKeyFile, char *szPVKFile, int nBits, int nExpFermat, int nTests, int nCount, char *szPassword, char *sSeed, int nSeedLen, int nOptions);
int RSA_ReadEncPrivateKey(char *szOutput, int nOutputLen, char *szPVKFile, char *szPassword, int nOptions);
int RSA_ReadPrivateKeyInfo(char *szOutput, int nOutputLen, char *szKeyFile, int nOptions);
int RSA_GetPrivateKeyFromPFX(char *szOutputFile, char *szPFXFile, int nOptions);
int RSA_ReadPublicKey(char *szOutput, int nOutputLen, char *szKeyFile, int flags);
int RSA_GetPublicKeyFromCert(char *szOutput, int nOutputLen, char *szCertFile, int flags);
int RSA_SavePublicKey(char *szFileOut, char *szKeyString, int nOptions);
int RSA_SavePrivateKeyInfo(char *szFileOut, char *szKeyString, int nOptions);
int RSA_SaveEncPrivateKey(char *szFileOut, char *szKeyString, int nCount, char *szPassword, int nOptions);
int RSA_KeyBits(char *szRsaKey64);
int RSA_KeyBytes(char *szRsaKey64);
int RSA_ToXMLString(char *szOutput, int nOutputLen, char *szKeyString, int nOptions);
int RSA_FromXMLString(char *szOutput, int nOutputLen, char *szXmlString, int nOptions);
int RSA_CheckKey(char *szKeyString, int nOptions);
/* 'RAW' RSA ENCRYPTION/DECRYPTION FUNCTIONS */
int RSA_RawPublic(ubyte *abData, int nDataLen, char *szPublicKey64, int nOptions);
int RSA_RawPrivate(ubyte *abData, int nDataLen, char *szPrivateKey64, int nOptions);
int RSA_EncodeMsg(ubyte *abOutput, int nOutputLen, ubyte *abMessage, int nMsgLen, int nOptions);
int RSA_DecodeMsg(ubyte *abOutput, int nOutputLen, ubyte *abInput, int nInputLen, int nOptions);
/* PKCS12 FILE FUNCTIONS */
int PFX_MakeFile(char *szFileOut, char *szCertFile, char *szKeyFile, char *szPassword, char *szFriendlyName, int options);
int PFX_VerifySig(char *szFileName, char *szPassword, int options);
/* X509 CERTIFICATE FUNCTIONS */
int X509_MakeCert(char *certfile, char *issuerCert, char *subjectPubkeyFile, char *issuerPvkInfoFile, int certnum, int yearsvalid, char *distName, char *email, int keyUsageFlags, char *password, int optionFlags);
int X509_MakeCertSelf(char *certfile, char *epkfile, int certnum, int yearsvalid, char *distName, char *email, int keyUsageFlags, char *password, int optionFlags);
int X509_CertRequest(char *reqfile, char *epkfile, char *distName, char *reserved, char *password, int optionFlags);
int X509_VerifyCert(char *szCertToVerify, char *szIssuerCert, int flags);
int X509_CertThumb(char *szCertFile, char *szHash, int nHashLen, int flags);
int X509_CertIsValidNow(char *szCertFile, int flags);
int X509_CertIssuedOn(char *szCertFile, char *szOutput, int nOutputLen, int flags);
int X509_CertExpiresOn(char *szCertFile, char *szOutput, int nOutputLen, int flags);
int X509_CertSerialNumber(char *szCertFile, char *szOutput, int nOutputLen, int flags);
int X509_HashIssuerAndSN(char *szCertFile, char *szOutput, int nOutputLen, int flags);
int X509_CertIssuerName(char *szCertFile, char *szOutput, int nOutputLen, char *szDelim, int flags);
int X509_CertSubjectName(char *szCertFile, char *szOutput, int nOutputLen, char *szDelim, int flags);
int X509_GetCertFromP7Chain(char *szNewCertFile, char *szP7cFile, int nIndex, int nOptions);
int X509_GetCertFromPFX(char *szNewCertFile, char *szPfxFile, char *szReserved, int nOptions);
int X509_QueryCert(char *szDataOut, int nDataOutLen, char *szFileIn, char *szQuery, int nOptions);
/* TRIPLE DES FUNCTIONS */
int TDEA_HexMode(char *output, char *input, char *szHexKey, int bEncrypt, char *szMode, char *sHexIV);
int TDEA_B64Mode(char *output, char *input, char *szB64Key, int bEncrypt, char *szMode, char *sB64IV);
int TDEA_BytesMode(ubyte *output, ubyte *input, int nbytes, ubyte *key, int bEncrypt, char *szMode, ubyte *iv);
int TDEA_File(char *szFileOut, char *szFileIn, ubyte *key, int bEncrypt, char *szMode, ubyte *iv);
/* MESSAGE DIGEST HASH FUNCTIONS */
int HASH_HexFromBytes(char *szHexDigest, int digLen, void *aMessage, int messageLen, int flags);
int HASH_HexFromFile(char *szHexDigest, int digLen, char *szFileName, int flags);
int HASH_Bytes(ubyte *digest, int digLen, void *aMessage, int messageLen, int flags);
int HASH_File(ubyte *digest, int digLen, char *szFileName, int flags);
/* MISC UTILITIES */
int WIPE_File(char *szFileName, int flags);
int WIPE_Data(void *lpData, int datalen);
int RNG_Bytes(ubyte *output, int out_len, char *seed, int seedlen);
int RNG_Number(int lower, int upper);
int PWD_Prompt(char *szPassword, int nPwdLen, char *szCaption);
int PWD_PromptEx(char *szPassword, int nPwdLen, char *szCaption, char *szPrompt, int flags);
/* BASE64 AND HEX CONVERSION FUNCTIONS */
int CNV_B64StrFromBytes(char *szOutput, int nOutChars, ubyte *input, int nbytes);
int CNV_BytesFromB64Str(ubyte *output, int out_len, char *input);
int CNV_B64Filter(char *szOutput, char *input, int len);
int CNV_HexStrFromBytes(char *szOutput, int nOutChars, ubyte *input, int nbytes);
int CNV_BytesFromHexStr(ubyte *output, int out_len, char *input);
int CNV_HexFilter(char *szOutput, char *input, int len);
/* UTF-8 CONVERSION/CHECK FUNCTIONS */
int CNV_UTF8FromLatin1(char *szOutput, int nOutChars, char *szInput);
int CNV_Latin1FromUTF8(char *szOutput, int nOutChars, char *szInput);
int CNV_CheckUTF8(char *szInput);
extern (D) :
private import std.string;
alias char[] String;
public enum Mode
{
///
/// Electronic Code Book mode
///
ECB,
///
/// Cipher Block Chaining mode
///
CBC,
///
/// Cipher Feedback mode
///
CFB,
///
/// Output Feedback mode
///
OFB,
///
/// Counter mode
///
CTR
}
///
/// Base for encoding methods
///
public enum EncodingBase
{
///
/// Base64 encoding
///
Base64,
///
/// Base16 encoding (i.e. hexadecimal)
///
Base16
}
///
/// Message Digest Hash Algorithm
///
public enum HashAlgorithm
{
///
/// SHA-1 (as per FIPS PUB 180-2)
///
Sha1 = 0,
///
/// MD5 (as per RFC 1321)
///
Md5 = 1,
///
/// MD2 (as per RFC 1319)
///
Md2 = 2,
///
/// SHA-256 (as per FIPS PUB 180-2)
///
Sha256 = 3
}
// Constants we use internally
enum Direction
{
Encrypt = 1,
Decrypt = 0
}
enum SignatureType
{
PKI_SIG_SHA1RSA = 0,
PKI_SIG_MD5RSA = 1,
PKI_SIG_MD2RSA = 2
}
enum Max
{
PKI_MAX_HASH_LEN = 64,
PKI_MAX_HASH_BYTES = 32
}
enum Emsig
{
PKI_EMSIG_DEFAULT = 0x20,
PKI_EMSIG_DIGESTONLY = 0x1000,
PKI_EMSIG_DIGINFO = 0x2000
}
///
/// General functions
///
public class General
{
public this() {} // Static methods only, so hide constructor.
/* GENERAL FUNCTIONS */
///
/// Gets licence type.
///
/// D=Developer P=Personal T=Trial
public char LicenceType()
{
int n = PKI_LicenceType(0);
return cast(char)n;
}
///
/// Retrieves the last error message set by the toolkit.
///
/// Final error message from last call (may be empty)
public String LastError()
{
String sb;
int n = PKI_LastError(null, 0);
sb.length = n;
.PKI_LastError(sb, sb.length);
sb = .toString(sb);
return sb;
}
///
/// Returns the error code of the first error that occurred when calling the last function
///
///
public int ErrorCode()
{
return PKI_ErrorCode();
}
///
/// Looks up error code
///
/// Code number
/// Corresponding error message
public String ErrorLookup(int errCode)
{
String sb;
sb.length = 128;
if (PKI_ErrorLookup(sb, sb.length, errCode)>0) {
sb = .toString(sb);
return sb;
}
else
return null;
}
///
/// Gets date and time the CryptoSys PKI DLL module was last compiled
///
/// Date and time String
public String CompileTime()
{
String sb;
sb.length = 65;
PKI_CompileTime(sb, sb.length);
sb = .toString(sb);
return sb;
}
///
/// Gets full path name of core CryptoSys PKI DLL module
///
/// File name
public String ModuleName()
{
String sb;
int n = PKI_ModuleName(sb, 0, 0);
sb.length = n;
PKI_ModuleName(sb, sb.length, 0);
sb = .toString(sb);
return sb;
}
///
/// Performs FIPS-140-2 start-up tests
///
/// Zero on success
public int PowerUpTests()
{
return PKI_PowerUpTests(0);
}
///
/// Returns version number of core CryptoSys PKI DLL.
///
/// Version number in form Major * 100 + Minor * 10 + Release
public int Version()
{
return PKI_Version(null, null);
}
}
///
/// Cryptographic Message Syntax (CMS) Functions
///
public class Cms
{
public this() {} // Static methods only, so hide constructor.
private const int PKI_CMS_FORMAT_BASE64 = 0x10000;
///
/// Options for CMS objects
///
public enum Options
{
///
/// Default option
///
Default = 0,
///
/// Exclude X.509 certs from output
///
ExcludeCerts = 0x0100,
///
/// Exclude data from output
///
ExcludeData = 0x0200,
///
/// Include Signed Attributes
///
IncludeAttributes = 0x0800,
///
/// Add signing time
///
AddSignTime = 0x1000,
///
/// Add S/MIME capabilities
///
AddSmimeCapabilities = 0x2000,
///
/// Create output/expect input in base64 format
///
FormatBase64 = 0x10000,
///
/// Use MD5 hash digest algorithm (default is SHA-1)
///
UseMD5 = 1,
///
/// Create a "naked" SignedData object with no outerContentInfo as permitted by PKCS#7 v1.6
///
NoOuter = 0x2000000,
///
/// Use alternative signature algorithm identifiers in SignedData object, e.g. 'sha1withRSAEncryption' instead of 'rsaEncryption'
///
AltAlgId = 0x4000000
}
/* RFC3852 CRYPTOGRAPHIC MESSAGE SYNTAX FUNCTIONS */
///
/// Creates an encrypted CMS enveloped-data object for one or more recipients using their x.509 certificates
///
/// Output file to be created
/// Input data file
/// List of X509 certificate filename(s), separated by semi-colons
///
/// Number of successful recipients or negative error code
public int MakeEnvData(String outputFile, String inputFile, String certList, Cms.Options options) {
return CMS_MakeEnvData(outputFile, inputFile, certList, "", 0, cast(int)options);
}
///
/// The same as Cms.MakeEnvData except the input data is in an ANSI String instead of a file
///
/// Output file to be created
/// Input data text
/// List of X509 certificate filename(s), separated by semi-colons
///
/// Number of successful recipients or negative error code
public int MakeEnvDataFromString(String outputFile, String inputData, String certList, Cms.Options options) {
return CMS_MakeEnvDataFromString(outputFile, inputData, certList, "", 0, cast(int)options);
}
///
/// Reads and decrypts CMS enveloped-data object using the recipient's private key.
///
/// Name of output file to be created
/// File that contains the CMS-enveloped data
/// (optional) specifies the filename of the recipient's X.509 certificate
/// Internal representation of private key
///
/// Zero if successful; otherwise it returns an error code
public int ReadEnvDataToFile(String outputFile, String inputFile, String x509File, String privateKey, Cms.Options options) {
return CMS_ReadEnvData(outputFile, inputFile, x509File, privateKey, cast(int)options);
}
///
/// Reads and decrypts CMS enveloped-data object using the recipient's private key
///
/// File that contains the CMS-enveloped data
/// (optional) specifies the filename of the recipient's X.509 certificate
/// Internal representation of private key
///
/// Message text or an empty String on error
public String ReadEnvDataToString(String inputFile, String x509File, String privateKey, Cms.Options options)
{
String sb;
int n = CMS_ReadEnvDataToString(sb, 0, inputFile, x509File, privateKey, cast(int)options);
if (n <= 0) return null;
sb.length = n;
CMS_ReadEnvDataToString(sb, sb.length, inputFile, x509File, privateKey, cast(int)options);
sb = .toString(sb);
return sb;
}
///
/// creates a CMS object of type SignedData from an input data file
/// ready for sending as part of an S/MIME email
///
/// name of output file to be created
/// name of file containing message data to be signed
/// containing the filename of the signer's
/// certificate and (optionally) a list of other certificates
/// to be included in the output, separated by semi-colons(;)
/// containing the private key data for the sender
/// option flags (default=0)
/// Zero if successful; otherwise it returns an error code
public int MakeSigData(String outputFile, String inputFile, String certList, String privateKey, Cms.Options options)
{
return CMS_MakeSigData(outputFile, inputFile, certList, privateKey, cast(int)options);
}
///
/// Creates a CMS object of type SignedData from an input String
///
/// name of output file to be created
/// String containing message data to be signed
/// containing the filename of the signer's
/// certificate and (optionally) a list of other certificates
/// to be included in the output, separated by semi-colons(;)
/// containing the private key data for the sender
/// option flags (default=0)
/// Zero if successful; otherwise it returns an error code
public int MakeSigDataFromString(String outputFile, String inputData, String certList, String privateKey, Cms.Options options)
{
return CMS_MakeSigDataFromString(outputFile, inputData, certList, privateKey, cast(int)options);
}
///
/// Creates a CMS object of type SignedData using a pre-computed signature
///
/// name of output file to be created
/// signature value
/// String containing content data that has been signed
/// containing the filename of the signer's
/// certificate and (optionally) a list of other certificates
/// to be included in the output, separated by semi-colons(;)
/// option flags (default=0)
/// Zero if successful; otherwise it returns an error code
public int MakeSigDataFromSigValue(String outputFile, ubyte[] sigValue, ubyte[] contentData, String certList, Cms.Options options)
{
return CMS_MakeSigDataFromSigValue(outputFile, sigValue, sigValue.length, contentData, contentData.length, certList, cast(int)options);
}
///
/// Creates a "detached signature" CMS signed-data object file
/// from a message digest of the content
///
/// name of output file to be created
/// String containing message digest in hex format
/// containing the filename of the signer's
/// certificate and (optionally) a list of other certificates
/// to be included in the output, separated by semi-colons(;)
/// containing the private key data for the sender
/// option flags (default=0)
/// Zero if successful; otherwise it returns an error code
public int MakeDetachedSig(String outputFile, String hexDigest, String certList, String privateKey, Cms.Options options)
{
return CMS_MakeDetachedSig(outputFile, hexDigest, certList, privateKey, cast(int)options);
}
///
/// Reads the content from a CMS signed-data object file
///
/// file to receive content
/// file containing CMS signed-data object
/// true if input is in base64 encoding;
/// false for binary BER-encoded
/// If successful, the return value is a positive number indicating the number of bytes in the content;
/// otherwise it returns a negative error code.
public int ReadSigDataToFile(String outputFile, String inputFile, bool inputIsBase64)
{
int flags = (inputIsBase64 ? PKI_CMS_FORMAT_BASE64 : 0);
return CMS_ReadSigData(outputFile, inputFile, flags);
}
///
/// Reads the content from a CMS signed-data object file directly into a String
///
/// file containing CMS signed-data object
/// true if input is in base64 encoding;
/// false for binary BER-encoded
/// String containing the content or an empty String if error
public String ReadSigDataToString(String inputFile, bool inputIsBase64)
{
int flags = (inputIsBase64 ? PKI_CMS_FORMAT_BASE64 : 0);
String sb;
int n = CMS_ReadSigDataToString(sb, 0, inputFile, flags);
if (n <= 0) return null;
sb.length = n;
CMS_ReadSigDataToString(sb, sb.length, inputFile, flags);
sb = .toString(sb);
return sb;
}
///
/// extracts the message digest from a signed-data CMS object file
/// and verifies the signature
///
/// file containing CMS signed-data object
/// an (optional) X.509 certificate file to be used to identify the signer
/// true if input is in base64 encoding;
/// false for binary BER-encoded
/// Hash value in hex format or an empty String if error
public String GetSigDataDigest(String inputFile, String certFile, bool inputIsBase64)
{
int flags = (inputIsBase64 ? PKI_CMS_FORMAT_BASE64 : 0);
// We know the max length of a hash digest
String sb;
sb.length = cast(int)Max.PKI_MAX_HASH_LEN;
int n = CMS_GetSigDataDigest(sb, sb.length, inputFile, certFile, flags);
// Return value is ID of hash algorithm or -ve error code
if (n < 0) return null;
sb = .toString(sb);
return sb;
}
///
/// Finds message digest hash algorithm used to make signature
///
/// file containing CMS signed-data object
/// an (optional) X.509 certificate file to be used to identify the signer
/// true if input is in base64 encoding;
/// false for binary BER-encoded
/// 0=SHA-1, 1=MD5, 2=MD2; or a negative error code
public int GetSigHashAlgorithm(String inputFile, String certFile, bool inputIsBase64)
{
int flags = (inputIsBase64 ? PKI_CMS_FORMAT_BASE64 : 0);
// We know the max length of a hash digest
String sb;
sb.length = cast(int)Max.PKI_MAX_HASH_LEN;
int n = CMS_GetSigDataDigest(sb, sb.length, inputFile, certFile, flags);
// Return value is ID of hash algorithm or -ve error code
return n;
}
///
/// Verifies the signature and content of a signed-data CMS object file.
///
/// file containing CMS signed-data object
/// an (optional) X.509 certificate file of the signer
/// (optional) digest of eContent to be verified
/// true if input is in base64 encoding;
/// false for binary BER-encoded
/// Zero if successfully verified; otherwise it returns an error code
public int VerifySigData(String inputFile, String certFile, String hexDigest, bool inputIsBase64)
{
int flags = (inputIsBase64 ? PKI_CMS_FORMAT_BASE64 : 0);
return CMS_VerifySigData(inputFile, certFile, hexDigest, flags);
}
///
/// Queries a CMS signed-data object file for selected information.
///
/// file containing CMS signed-data object
/// query String
/// true if input is in base64 encoding;
/// false for binary BER-encoded
/// String containing the result or an empty String if not found or error
public String QuerySigData(String inputFile, String query, bool inputIsBase64)
{
int flags = (inputIsBase64 ? PKI_CMS_FORMAT_BASE64 : 0);
String sb;
int n = CMS_QuerySigData(sb, 0, inputFile, query, flags);
if (n <= 0) return null;
sb.length = n;
int x = CMS_QuerySigData(sb, sb.length, inputFile, query, flags);
// CMS_QuerySigData either returns an integer result directly or sets the String
sb = .toString(sb);
if (sb.length == 0){ // Result is an integer returned in n, so set our return value as a String
//sb.Append(n);
sb ~= .toString(n);
}
return sb;
}
}
///
/// RSA Encryption and Public Key Functions
///
public class Rsa
{
public this(){} // Static methods only, so hide constructor.
private const int KEYGEN_INDICATE = 0x10;
private const int PKI_KEY_FORMAT_PEM = 0x10000;
private const int PKI_KEY_FORMAT_SSL = 0x20000;
private const int PKI_XML_RSAKEYVALUE = 0x0001;
private const int PKI_XML_EXCLPRIVATE = 0x0010;
private const int PKI_XML_HEXBINARY = 0x0100;
///
/// Password-based Encryption options to indicate the algorithm to be used to encrypt the private key file
///
/// See PKCS#5 v2.0 or RFC 2898
public enum PbeOptions
{
///
/// Default option (pbeWithSHAAnd3-KeyTripleDES-CBC)
///
Default = 0,
///
/// pbeWithSHAAnd3-KeyTripleDES-CBC
///
PbeWithSHAAnd_KeyTripleDES_CBC = 0,
///
/// pbeWithMD5AndDES-CBC
///
PbeWithMD5AndDES_CBC = 1,
///
/// pbeWithMD2AndDES-CBC
///
PbeWithMD2AndDES_CBC = 2,
///
/// pbeWithSHA1AndDES-CBC
///
PbeWithSHA1AndDES_CBC = 3,
///
/// "pkcs5PBES2" with "des-EDE3-CBC"
///
Pkcs5PBES2_des_EDE3_CBC = 4
}
///
/// Choices for public exponent (e)
///
/// Fermat Number F(x) = 2^(2^x) + 1. F0 to F4 are prime.
public enum PublicExponent
{
///
/// Set exponent equal to 3 (F0)
///
Exp_EQ_3 = 0,
///
/// Set exponent equal to 5 (F1)
///
Exp_EQ_5 = 1,
///
/// Set exponent equal to 17 (F2)
///
Exp_EQ_17 = 2,
///
/// Set exponent equal to 257 (F3)
///
Exp_EQ_257 = 3,
///
/// Set exponent equal to 65537 (F4)
///
Exp_EQ_65537 = 4
}
///
/// Format for saved RSA key
///
public enum Format
{
///
/// Default = Binary
///
Default = 0,
///
/// Binary DER-encoded
///
Binary = 0,
///
/// PEM Format
///
PEM = PKI_KEY_FORMAT_PEM,
///
/// PEM format compatible with OpenSLL
///
SSL = PKI_KEY_FORMAT_SSL
}
// No of Rabin-Miller primality tests to perform
// - this gives a probablity of 2^-128 of a wrong answer.
private const int PRIME_TESTS = 64;
/* RSA KEY FUNCTIONS */
///
/// Generate an RSA public/private key pair
///
/// Output filename for public key
/// Output filename for (encrypted) private key
/// Required key modulus size in bits (min 96)
/// Exponent (Fermat Prime)
/// Iteration count for encrypted private key
/// Password String for encrypted private key
/// Option to specify encryption algorithm for private key
/// Indicate progress in console
/// Zero if successful or non-zero error code
public int MakeKeys(String publicKeyFile, String privateKeyFile, int bits, PublicExponent exponent, int iterCount, String password, Rsa.PbeOptions cryptOption, bool showProgress)
{
int flags = (showProgress ? KEYGEN_INDICATE : 0) | cast(int)cryptOption;
return RSA_MakeKeys(publicKeyFile, privateKeyFile, bits, cast(int)exponent, PRIME_TESTS, iterCount, password, "", 0, flags);
}
///
/// Reads encrypted private key file into internal String format
///
/// filename of a binary BER-encoded encrypted private key info file
///
/// String containing an internal representation of the
/// private key; or an empty String if error
/// This returns a String, not a String, so it can
/// be properly wiped later.
public String ReadEncPrivateKey(String privateKeyFile, String password)
{
String sb;
int n = RSA_ReadEncPrivateKey(sb, 0, privateKeyFile, password, 0);
if (n <= 0) {
return null;
}
sb.length = n;
RSA_ReadEncPrivateKey(sb, sb.length, privateKeyFile, password, 0);
sb = .toString(sb);
return sb;
}
///
/// Reads from an (unencrypted) PKCS-8 private key info file into a private key String
///
/// Name of file
/// String containing an internal representation of the
/// private key; or an empty String if error
/// This returns a String, not a String, so it can
/// be properly wiped later.
public String ReadPrivateKeyInfo(String prikeyinfoFile)
{
String sb;
int n = RSA_ReadPrivateKeyInfo(sb, 0, prikeyinfoFile, 0);
if (n <= 0) {
return null;
}
sb.length = n;
RSA_ReadPrivateKeyInfo(sb, sb.length, prikeyinfoFile, 0);
sb = .toString(sb);
return sb;
}
///
/// Extracts an encrypted private key from a PKCS-12 PKCS8ShroudedKeyBag,
/// saving the output directly as a new file
///
/// Name of new file to create
/// PKCS-12 filename
/// If successful, it returns the number of bytes written to the output file;
/// otherwise it returns a negative error code
public int GetPrivateKeyFromPFX(String outputFile, String pfxFile)
{
return RSA_GetPrivateKeyFromPFX(outputFile, pfxFile, 0);
}
///
/// Reads public key file into internal String format
///
/// filename of BER-encoded public key data
/// String containing an internal representation of the
/// public key; or an empty String if error
/// This returns a String, not a String, so it can
/// be properly wiped later.
public String ReadPublicKey(String keyFile)
{
String sb;
int n = RSA_ReadPublicKey(sb, 0, keyFile, 0);
if (n <= 0) {
return null;
}
sb.length = n;
RSA_ReadPublicKey(sb, sb.length, keyFile, 0);
sb = .toString(sb);
return sb;
}
///
/// Gets public key from X.509 certificate into internal String format
///
///
/// String containing an internal representation of the
/// public key; or an empty String if error
/// This returns a String, not a String, so it can
/// be properly wiped later.
public String GetPublicKeyFromCert(String certFile)
{
String sb;
int n = RSA_GetPublicKeyFromCert(sb, 0, certFile, 0);
if (n <= 0) {
return null;
}
sb.length = n;
RSA_GetPublicKeyFromCert(sb, sb.length, certFile, 0);
sb = .toString(sb);
return sb;
}
///
/// Saves a public key String to PKCS-1 public key file
///
/// Name of file to create
/// Public key in internal format
/// File format
/// If successful, the return value is zero; otherwise it returns an error cod
public int SavePublicKey(String outputFile, String publicKey, Rsa.Format format)
{
return RSA_SavePublicKey(outputFile, publicKey, cast(int)format);
}
///
/// Saves a private key String to an (unencrypted) PKCS-8 private key info file
///
/// Name of file to create
/// Private key in internal format
/// File format
/// If successful, the return value is zero; otherwise it returns an error cod
public int SavePrivateKeyInfo(String outputFile, String privateKey, Rsa.Format format)
{
return RSA_SavePrivateKeyInfo(outputFile, privateKey, cast(int)format);
}
///
///
///
/// Name of file to create
/// Private key in internal format
/// Count to be used when encrypting file
///
/// Type of password-based encryption to use
/// (default = pbeWithSHAAnd3-KeyTripleDES-CBC)
/// File format
/// If successful, the return value is zero; otherwise it returns an error cod
public int SaveEncPrivateKey(String outputFile, String privateKey, int iterationCount, String password, Rsa.PbeOptions pbeOption, Rsa.Format format)
{
int flags = cast(int)pbeOption | cast(int)format;
return RSA_SaveEncPrivateKey(outputFile, privateKey, iterationCount, password, flags);
}
///
/// Returns number of significant bits in RSA key modulus
///
///
/// Number of significant bits
public int KeyBits(String strRsaKey)
{
return RSA_KeyBits(strRsaKey);
}
///
/// Returns number of bytes (octets) in RSA key modulus
///
///
/// Number of bytes
public int KeyBytes(String strRsaKey)
{
return RSA_KeyBytes(strRsaKey);
}
///
/// Check the validity of an "internal" RSA public or private key
///
/// Internal key String
/// 0=valid private key, 1=valid publickey, or negative error code
/// A private key is also validated for consistency.
public int CheckKey(String intKeychar)
{
return RSA_CheckKey(intKeychar, 0);
}
///
/// Options when exporting RSA key to XML
///
public enum XmlOptions
{
///
/// Exclude private key parameters
///
ExcludePrivateParams = PKI_XML_EXCLPRIVATE,
///
/// Create in .NET-compatible RSAKeyValue format
///
ForceRSAKeyValue = PKI_XML_RSAKEYVALUE,
///
/// Create in non-standard hex format
///
HexBinaryFormat = PKI_XML_HEXBINARY
}
///
/// Creates an XML String representation of an RSA internal key String
///
///
///
/// XML String or empty String on error
public String ToXMLString(String intKeychar, XmlOptions options)
{
String sb;
int n = RSA_ToXMLString(sb, 0, intKeychar, cast(int)options);
if (n <= 0) return null;
sb.length = n;
RSA_ToXMLString(sb, sb.length, intKeychar, cast(int)options);
sb = .toString(sb);
return sb;
}
///
/// Creates an RSA key String in internal format from an XML String
///
/// The XML String to use to reconstruct the RSA key
/// Reconstruct public key details only
/// Key String in internal format or empty String on error
public String FromXMLString(String xmlchar, bool excludePrivateParams)
{
String sb;
int option = (excludePrivateParams ? PKI_XML_EXCLPRIVATE : 0);
int n = RSA_FromXMLString(sb, 0, xmlchar, option);
if (n <= 0) return null;
sb.length = n;
RSA_FromXMLString(sb, sb.length, xmlchar, cast(int)option);
sb = .toString(sb);
return sb;
}
/* 'RAW' RSA ENCRYPTION/DECRYPTION FUNCTIONS */
///
/// Carries out RSA transformation using public key
///
/// Data (must be same byte length as key modulus)
/// Public key in internal String format
/// Transformed data
public ubyte[] RawPublic(ubyte[] data, String publicKeyStr)
{
ubyte[] b;
b.length = data.length;
b = data;
int r = RSA_RawPublic(b, b.length, publicKeyStr, 0);
if (r != 0) return null;
return b;
}
///
/// Carries out RSA transformation using private key
///
/// Data (must be same byte length as key modulus)
/// Private key in internal String format
/// Transformed data
public ubyte[] RawPrivate(ubyte[] data, String privateKeyStr)
{
ubyte[] b;
b.length = data.length;
b = data;
int r = RSA_RawPrivate(b, b.length, privateKeyStr, 0);
if (r != 0) return null;
return b;
}
///
/// Type of encoding to apply (or use to decode). Deprecated.
///
public enum EncodeFor
{
///
/// EME-PKCS1-V1_5
///
Encryption = 0,
///
/// EME-OAEP
///
Encryption_OAEP = 0x10,
///
/// EMSA-PKCS1-V1_5 (using SHA-1)
///
Signature = 0x20
}
///
/// Encoding method for encryption
///
/// See PKCS#1 v2.1 or RFC 3447
public enum EME
{
///
/// EME-PKCS1-v1_5 encoding method
///
PKCSv1_5 = 0,
///
/// EME-OAEP encoding method
///
OAEP = 0x10
}
///
/// Encode a message ready for "raw" RSA encryption or signing. Deprecated.
///
/// Size of RSA key in bytes
/// Message data
/// Method to use
/// Encoded message block
/// Deprecated. Use EncodeMsgForEncryption
/// or EncodeMsgForSignature or EncodeDigestForSignature
public ubyte[] EncodeMsg(int keyBytes, ubyte[] message, Rsa.EncodeFor method)
{
if (keyBytes <= 0) return null;
ubyte[] b;
b.length = keyBytes;
int r = RSA_EncodeMsg(b, b.length, message, message.length, cast(int)method);
if (r != 0) return null;
return b;
}
///
/// Decode a PKCS-1 encoded block. Deprecated.
///
///
///
/// Decoded data
/// Deprecated. Use DecodeMsgForEncryption or DecodeDigestForSignature
public ubyte[] DecodeMsg(ubyte[] data, Rsa.EncodeFor method)
{
int n = RSA_DecodeMsg(null, 0, data, data.length, cast(int)method);
if (n <= 0) return null;
ubyte[] b;
b.length = n;
n = RSA_DecodeMsg(b, b.length, data, data.length, cast(int)method);
if (n < 0) return null;
return b;
}
// NEW PKCS1 ENCODING AND DECODING FUNCTIONS [2006-07-27]
///
/// Encode a message for encryption
///
/// Number of bytes in the key
/// Message to be encoded
/// Encoding method to use
/// Encoded message block
public ubyte[] EncodeMsgForEncryption(int keyBytes, ubyte[] message, Rsa.EME method)
{
if (keyBytes <= 0) return null;
ubyte[] b;
b.length = keyBytes;
int r = RSA_EncodeMsg(b, b.length, message, message.length, cast(int)method);
if (r != 0) return null;
return b;
}
///
/// Decode a message for encryption
///
/// Encoded message
/// Encoding method used
/// Decoded message
public ubyte[] DecodeMsgForEncryption(ubyte[] data, Rsa.EME method)
{
int n = RSA_DecodeMsg(null, 0, data, data.length, cast(int)method);
if (n <= 0) return null;
ubyte[] b;
b.length = n;
n = RSA_DecodeMsg(b, b.length, data, data.length, cast(int)method);
if (n < 0) return null;
return b;
}
///
/// Encode a message for signature
///
/// Number of bytes in the key
/// Message to be encoded
/// Message digest algorithm to use
/// Encoded block
/// Only EMSA-PKCS1-v1_5 is supported.
/// Note we can only ever recover the digest from the
/// encoded block.
public ubyte[] EncodeMsgForSignature(int keyBytes, ubyte[] message, HashAlgorithm hashAlg)
{
int options = cast(int)hashAlg + cast(int)Emsig.PKI_EMSIG_DEFAULT;
if (keyBytes <= 0) return null;
ubyte[] b;
b.length = keyBytes;
int r = RSA_EncodeMsg(b, b.length, message, message.length, options);
if (r != 0) return null;
return b;
}
///
/// Encode a message digest for signature
///
/// Number of bytes in the key
/// Digest of message
/// Message digest algorithm used to create digest
/// Encoded block
/// Only EMSA-PKCS1-v1_5 is supported.
public ubyte[] EncodeDigestForSignature(int keyBytes, ubyte[] digest, HashAlgorithm hashAlg)
{
int options = cast(int)hashAlg + cast(int)Emsig.PKI_EMSIG_DEFAULT + cast(int)Emsig.PKI_EMSIG_DIGESTONLY;
if (keyBytes <= 0) return null;
ubyte[] b;
b.length = keyBytes;
int r = RSA_EncodeMsg(b, b.length, digest, digest.length, options);
if (r != 0) return null;
return b;
}
///
/// Decode an encoded message for signature
///
/// Encoded message for signature
/// Decoded message digest or an empty array on error
/// Only EMSA-PKCS1-v1_5 is supported.
public ubyte[] DecodeDigestForSignature(ubyte[] data)
{
const int options = cast(int)Emsig.PKI_EMSIG_DEFAULT;
int n = RSA_DecodeMsg(null, 0, data, data.length, options);
if (n <= 0) return null;
ubyte[] b;
b.length = n;
n = RSA_DecodeMsg(b, b.length, data, data.length, options);
if (n < 0) return null;
return b;
}
///
/// Decode an encoded message for signature
///
/// Encoded message for signature
/// If true, extract the full DigestInfo;
/// otherwise just extract the message digest itself
/// Decoded data or an empty array on error
/// Only EMSA-PKCS1-v1_5 is supported.
public ubyte[] DecodeDigestForSignature(ubyte[] data, bool getFullDigestInfo)
{
int options;
if (getFullDigestInfo)
options = cast(int)Emsig.PKI_EMSIG_DEFAULT + cast(int)Emsig.PKI_EMSIG_DIGINFO;
else
options = cast(int)Emsig.PKI_EMSIG_DEFAULT;
int n = RSA_DecodeMsg(null, 0, data, data.length, options);
if (n <= 0) return null;
ubyte[] b;
b.length = n;
n = RSA_DecodeMsg(b, b.length, data, data.length, options);
if (n < 0) return null;
return b;
}
}
///
/// PKCS-12 (PFX) File Functions
///
public class Pfx
{
private const int PKI_PFX_NO_PRIVKEY = 0x10;
public this(){} // Static methods only, so hide constructor.
/* PKCS12 FILE FUNCTIONS */
///
/// Creates a simple PFX (PKCS-12) file from an X.509 certificate and (optional) encrypted private key file
///
/// name of output file to be created
/// filename of the subject's X.509 certificate (required in all cases)
/// filename of the subject's encrypted private key in pkcs-8 format
///
/// friendly name identification for the subject (required)
/// true to exclude the private key data (i.e. just include the certificate)
///
public int MakeFile(String fileToMake, String certFile, String privateKeyFile, String password, String friendlyName, bool excludePrivateKey)
{
return PFX_MakeFile(fileToMake, certFile, privateKeyFile, password, friendlyName, (excludePrivateKey ? 1 : 0));
}
///
/// Verifies that the MacData signature in PKCS-12 file is OK
///
/// Name of PKCS-12 file to be checked
///
/// true if signature is OK
public bool SignatureIsValid(String fileName, String password)
{
int r = PFX_VerifySig(fileName, password, 0);
return (0 == r ? true : false);
}
}
///
/// X.509 Certificate Functions
///
public class X509
{
public this(){} // Static methods only, so hide constructor.
///
/// Options to create X.509 certificate/certificate request
///
public enum Options
{
///
/// Default options
///
None = 0,
///
/// Sign with sha1WithRSAEncryption
///
SigAlg_Sha1WithRSAEncryption = 0,
///
/// Sign with md5WithRSAEncryption
///
SigAlg_Md5WithRSAEncryption = 1,
///
/// Sign with md2WithRSAEncryption
///
SigAlg_Md2WithRSAEncryption = 2,
///
/// Create in PEM (base64) format (default for CSR request)
///
FormatPem = 0x10000,
///
/// Create in binary format (default for certificate)
///
FormatBinary = 0x20000,
///
/// Create a request with the "kludge" that omits the strictly mandatory attributes completely
/// (default = include attributes with zero-length field)
///
RequestKludge = 0x100000,
///
/// Disable the BasicConstraints extension (default = include)
///
NoBasicConstraints = 0x2000000,
///
/// Set the BasicConstraints subject type to be a CA (default = End Entity)
///
SetAsCA = 0x4000000,
///
/// Create a Version 1 certificate, i.e. no extensions (default = Version 3)
///
VersionOne = 0x8000000
}
///
/// Options for key usage in certificate
///
/// These should be self-explanatory
public enum KeyUsageOptions
{
///
///
///
None = 0,
///
///
///
DigitalSignature = 0x0001,
///
///
///
NonRepudiation = 0x0002,
///
///
///
KeyEncipherment = 0x0004,
///
///
///
DataEncipherment = 0x0008,
///
///
///
KeyAgreement = 0x0010,
///
///
///
KeyCertSign = 0x0020,
///
///
///
CrlSign = 0x0040,
///
///
///
EncipherOnly = 0x0080,
///
///
///
DecipherOnly = 0x0100
}
/* X509 CERTIFICATE FUNCTIONS */
///
/// Creates a new X.509 certificate using subject's public key and issuer's private key files.
///
/// Name of file to be created
///
/// File containing subjects public key data
/// File containing issuer's private key data
/// Issue number for new certificate
/// How many years to be valid
/// Distinguished name String
/// Optional RFC822 email address
/// Key usage options
/// For issuer's private key
///
/// Zero if successful or error code
public int MakeCert(String certFile, String issuerCert,
String subjectPubkeyFile, String issuerPvkInfoFile,
int certNum, int yearsValid, String distName, String email,
KeyUsageOptions keyUsageOptions, String password, Options options)
{
return X509_MakeCert(certFile, issuerCert,
subjectPubkeyFile, issuerPvkInfoFile,
certNum, yearsValid, distName, email,
cast(int)keyUsageOptions, password, cast(int)options);
}
///
/// Creates a self-signed X.509 certificate
///
///
///
///
///
///
///
///
///
///
/// Zero if successful or error code
public int MakeCertSelf(String certFile, String privateKeyFile,
int certNum, int yearsValid, String distName, String email,
KeyUsageOptions keyUsageOptions, String password, Options options)
{
return X509_MakeCertSelf(certFile, privateKeyFile,
certNum, yearsValid, distName, email,
cast(int)keyUsageOptions, password, cast(int)options);
}
///
/// Creates a PKCS #10 certificate signing request (CSR) using the subject's private key file
///
/// Name of Certificate Signing Request file to be created
/// Name of subject's encrypted private key file
/// Specifying the subject's distinguished name as a set of attribute key=value pairs
/// separated with semi-colons (;)
/// password for Subject's encrypted private key file
///
/// Zero if successful or error code
public int CertRequest(String reqFile, String privateKeyFile,
String distName, String password, Options options)
{
return X509_CertRequest(reqFile, privateKeyFile,
distName, "", password, cast(int)options);
}
///
/// Verifies that an X.509 certificate has been signed by its issuer
///
/// Filename of certificate to verify
/// Filename of purported issuer's certificate
/// Zero if the certificate's signature is valid; -1 if the validation fails; otherwise an error code.
public int VerifyCert(String certToVerify, String issuerCert)
{
return X509_VerifyCert(certToVerify, issuerCert, 0);
}
///
/// Calculates the thumbprint (message digest hash) of an X.509 certificate
///
/// Path to file
/// HashAlgorithm
/// String containing the message digest in hexadecimal format
public String CertThumb(String certFile, HashAlgorithm hashAlg)
{
String sb;
int n = X509_CertThumb(certFile, sb, 0, cast(int)hashAlg);
if (n <= 0) return null;
sb.length = n;
X509_CertThumb(certFile, sb, sb.length, cast(int)hashAlg);
sb = .toString(sb);
return sb;
}
///
/// Verifies that an X.509 certificate is currently valid as per system clock
///
/// Certificate filename
/// True if certificate is currently valid, otherwise false
public bool CertIsValidNow(String certFile)
{
// We fudge the subtleties of time validity and invalid format
int r = X509_CertIsValidNow(certFile, 0);
return (r == 0);
}
///
/// Returns date and time certificate was issued
///
///
/// Date and time in ISO format or Empty String if error
public String CertIssuedOn(String certFile)
{
String sb;
int n = X509_CertIssuedOn(certFile, sb, 0, 0);
if (n <= 0) return null;
sb.length = n;
X509_CertIssuedOn(certFile, sb, sb.length, 0);
sb = .toString(sb);
return sb;
}
///
/// Returns date and time certificate expires
///
///
/// Date and time in ISO format or Empty String if error
public String CertExpiresOn(String certFile)
{
String sb;
int n = X509_CertExpiresOn(certFile, sb, 0, 0);
if (n <= 0) return null;
sb.length = n;
X509_CertExpiresOn(certFile, sb, sb.length, 0);
sb = .toString(sb);
return sb;
}
///
/// Returns serial number in hex format
///
///
/// Serial number in hex format or Empty String if error
public String CertSerialNumber(String certFile)
{
String sb;
int n = X509_CertSerialNumber(certFile, sb, 0, 0);
if (n <= 0) return null;
sb.length = n;
X509_CertSerialNumber(certFile, sb, sb.length, 0);
sb = .toString(sb);
return sb;
}
///
/// Creates a message digest of the Issuer's name and the cert serial number
///
///
/// Hash algorithm to use (default SHA-1)
/// Message digest in hex format or Empty String if error
/// This (should) give a unique identifier for any certificate
public String HashIssuerAndSN(String certFile, HashAlgorithm algorithm)
{
String sb;
int n = X509_HashIssuerAndSN(certFile, sb, 0, cast(int)algorithm);
if (n <= 0) return null;
sb.length = n;
X509_HashIssuerAndSN(certFile, sb, sb.length, cast(int)algorithm);
sb = .toString(sb);
return sb;
}
///
/// Gets the issuer name of an X.509 certificate
///
/// Certificate filename
/// Default is semicolon ";"
/// Issuer name or Empty String if error
public String CertIssuerName(String certFile, String delimiter)
{
String sb;
int n = X509_CertIssuerName(certFile, sb, 0, delimiter, 0);
if (n <= 0) return null;
sb.length = n;
X509_CertIssuerName(certFile, sb, sb.length, delimiter, 0);
sb = .toString(sb);
return sb;
}
///
/// Gets the subject name of an X.509 certificate
///
/// Certificate filename
/// Default is semicolon ";"
/// Subject name or Empty String if error
public String CertSubjectName(String certFile, String delimiter)
{
String sb;
int n = X509_CertSubjectName(certFile, sb, 0, delimiter, 0);
if (n <= 0) return null;
sb.length = n;
X509_CertSubjectName(certFile, sb, sb.length, delimiter, 0);
sb = .toString(sb);
return sb;
}
///
/// Extracts an X.509 certificate from a PKCS-7 "certs-only" certificate chain file,
/// saving the output directly as a new file.
///
/// Name of output file to be created
/// Name of the PKCS-7 "certs-only" file
/// specifying which certificate (1,2,...) in the chain to extract, or 0 to return the count of certificates in the set
/// If successful and index is greater than zero, it returns the number of bytes written to the output file,
/// which may be zero if no certificate could be found at the given index.
/// However, if index is zero, it returns the count of certificates found in the list.
/// If an error occurred, it returns a negative error code.
/// Refer to the manual for further information and remarks on the use of this function.
public int GetCertFromP7Chain(String outputFile, String inputFile, int index)
{
return X509_GetCertFromP7Chain(outputFile, inputFile, index, 0);
}
///
/// Extracts an X.509 certificate from a PKCS-12 PFX/.p12 file,
/// saving the output directly as a new file.
///
/// Name of output file to be created
/// Name of the PKCS-12 file
/// If successful, it returns the number of bytes written to the output file; otherwise it returns a negative error code
/// Refer to the manual for further information and remarks on the use of this function.
public int GetCertFromPFX(String outputFile, String inputFile)
{
return X509_GetCertFromPFX(outputFile, inputFile, "", 0);
}
}
///
/// Character conversion routines
///
public class Cnv
{
public this(){} // Static methods only, so hide constructor.
// HEX CONVERSION PROTOTYPES
///
/// Converts 8-bit binary data to equivalent hexadecimal String format
///
///
///
public String ToHex(ubyte[] binaryData)
{
int nBytes = binaryData.length;
int nChars = 2 * nBytes;
if (nBytes == 0) return null;
String sb;
sb.length = nChars;
nChars = CNV_HexStrFromBytes(sb, nChars, binaryData, nBytes);
sb = .toString(sb);
return sb;
}
///
/// Converts the specified String representation of a value consisting of hexadecimal (base 16) digits to an equivalent array of 8-bit unsigned integers.
///
///
///
public ubyte[] FromHex(String s)
{
if (s == null) return null;
int nBytes = s.length / 2;
ubyte[] Data;
Data.length = nBytes;
nBytes = CNV_BytesFromHexStr(Data, nBytes, s);
if(Data.length != nBytes)
{
Data = Data[0..nBytes];
}
return Data;
}
///
/// Filters non-hexadecimal characters from a String
///
///
/// Filtered String
public String HexFilter(String s)
{
int nChars;
if (s == null) return null;
String sb;
sb.length = s.length;
nChars = CNV_HexFilter(sb, s, s.length);
if (nChars <= 0) return null;
sb = .toString(sb);
return sb;
}
/* BASE64 CONVERSION FUNCTIONS */
///
/// Filters non-base64 characters from a String
///
///
/// Filtered String
public String Base64Filter(String s)
{
int nChars;
if (s == null) return null;
String sb;
sb.length = s.length;
nChars = CNV_B64Filter(sb, s, s.length);
if (nChars <= 0) return null;
sb = .toString(sb);
return sb;
}
/* UTF-8 FUNCTIONS */
///
/// Checks that a String contains only valid UTF-8 encoded characters
///
/// input String to check
/// Zero if the String is invalid UTF-8,
/// or a positive number if the String is valid UTF-8, where the value of the
/// number indicates the nature of the encoded characters:
///
/// - 0Not valid UTF-8
/// - 1Valid UTF-8, all chars are 7-bit ASCII
/// - 2Valid UTF-8, contains at least one 8-bit ANSI character
/// - 3Valid UTF-8, contains at least one multi-byte character
/// that cannot be represented in a single-byte character set
///
///
///
///`Overlong' UTF-8 sequences and illegal surrogates are rejected as invalid.
///
public int CheckUTF8(String s)
{
return CNV_CheckUTF8(s);
}
}
///
/// Triple DES Cipher (3DES, TDEA)
///
public class Tdea
{
private Cnv cnv;
public this(){
cnv = new Cnv;
}
public ~this(){
cnv = null;
}
/* TRIPLE DES FUNCTIONS */
///
/// Block size in bytes
///
public const int BlockSize = 8;
// A common internal function to return the required String for the mode
public String ModeString(Mode mode) {
switch(mode)
{
case Mode.CBC:
return "CBC";
case Mode.CFB:
return "CFB";
case Mode.OFB:
return "OFB";
case Mode.CTR:
return "CTR";
case Mode.ECB:
default:
return "ECB";
}
}
///
/// Encrypt data in byte array
///
/// Input data
/// Key of exactly 24 bytes (192 bits)
/// Cipher Mode
/// IV of exactly 8 bytes or null for ECB mode
/// Ciphertext in byte array or empty array on error
/// For ECB and CBC modes, input data length must be an exact multiple of the block length
/// Three overloads: one for bytes, one for hex, one for general encoding
public ubyte[] Encrypt(ubyte[] input, ubyte[] key, Mode mode, ubyte[] iv)
{
String strMode = ModeString(mode);
ubyte[] b;
b.length = input.length;
int r = TDEA_BytesMode(b, input, input.length, key, cast(int)Direction.Encrypt, strMode, iv);
if (r != 0)
b = null;
return b;
}
///
/// Decrypt data in byte array
///
/// Input data
/// Key of exactly 24 bytes (192 bits)
/// Cipher Mode
/// IV of exactly 8 bytes or null for ECB mode
/// Decrypted data in byte array or empty array on error
/// For ECB and CBC modes, input data length must be an exact multiple of the block length
/// Three overloads: one for bytes, one for hex, one for general encoding
public ubyte[] Decrypt(ubyte[] input, ubyte[] key, Mode mode, ubyte[] iv)
{
String strMode = ModeString(mode);
ubyte[] b;
b.length = input.length;
int r = TDEA_BytesMode(b, input, input.length, key, cast(int)Direction.Decrypt, strMode, iv);
if (r != 0)
b = null;
return b;
}
///
/// Encrypt hex-encoded data String
///
/// Hex-encoded input data
/// Hex-encoded key representing exactly 24 bytes (192 bits)
/// Cipher Mode
/// Hex-encoded IV representing exactly 8 bytes or "" for ECB mode
/// Ciphertext in hex-encoded String or empty String on error
/// For ECB and CBC modes, the length of the decoded input bytes must be an exact multiple of the block length
public String Encrypt(String inputHex, String keyHex, Mode mode, String ivHex)
{
String strMode = ModeString(mode);
String sb;
sb.length = inputHex.length;
int r = TDEA_HexMode(sb, inputHex, keyHex, cast(int)Direction.Encrypt, strMode, ivHex);
if (r != 0) return null;
sb = .toString(sb);
return sb;
}
///
/// Decrypt hex-encoded data String
///
/// Hex-encoded input data
/// Hex-encoded key representing exactly 24 bytes (192 bits)
/// Cipher Mode
/// Hex-encoded IV representing exactly 8 bytes or "" for ECB mode
/// Decrypted data in hex-encoded String or empty String on error
/// For ECB and CBC modes, the length of the decoded input bytes must be an exact multiple of the block length
public String Decrypt(String inputHex, String keyHex, Mode mode, String ivHex)
{
String strMode = ModeString(mode);
String sb;
sb.length = inputHex.length;
int r = TDEA_HexMode(sb, inputHex, keyHex, cast(int)Direction.Decrypt, strMode, ivHex);
if (r != 0) return null;
sb = .toString(sb);
return sb;
}
///
/// Encrypt encoded data String
///
/// Encoded input data
/// Encoded key representing exactly 24 bytes (192 bits)
/// Cipher Mode
/// Encoded IV representing exactly 8 bytes or "" for ECB mode
/// Type of encoding used
/// Ciphertext in hex-encoded String or empty String on error
/// For ECB and CBC modes, the length of the decoded input bytes must be an exact multiple of the block length
public String Encrypt(String inputStr, String keyStr, Mode mode, String ivStr, EncodingBase encodingBase)
{
String strMode = ModeString(mode);
String sb;
sb.length = inputStr.length;
int r = -999;
switch(encodingBase)
{
case EncodingBase.Base16:
r = TDEA_HexMode(sb, inputStr, keyStr, cast(int)Direction.Encrypt, strMode, ivStr);
break;
case EncodingBase.Base64:
r = TDEA_B64Mode(sb, inputStr, keyStr, cast(int)Direction.Encrypt, strMode, ivStr);
break;
}
if (r != 0) return null;
sb = .toString(sb);
return sb;
}
///
/// Decrypt encoded data String
///
/// Encoded input data
/// Encoded key representing exactly 24 bytes (192 bits)
/// Cipher Mode
/// Encoded IV representing exactly 8 bytes or "" for ECB mode
/// Type of encoding used
/// Decrypted data in encoded String or empty String on error
/// For ECB and CBC modes, the length of the decoded input bytes must be an exact multiple of the block length
public String Decrypt(String inputStr, String keyStr, Mode mode, String ivStr, EncodingBase encodingBase)
{
String strMode = ModeString(mode);
String sb;
sb.length = inputStr.length;
int r = -999;
switch(encodingBase)
{
case EncodingBase.Base16:
r = TDEA_HexMode(sb, inputStr, keyStr, cast(int)Direction.Decrypt, strMode, ivStr);
break;
case EncodingBase.Base64:
r = TDEA_B64Mode(sb, inputStr, keyStr, cast(int)Direction.Decrypt, strMode, ivStr);
break;
}
if (r != 0) return null;
sb = .toString(sb);
return sb;
}
///
/// Encrypt a file
///
/// Name of output file to be created or overwritten
/// Name of input file
/// Key of exactly 24 bytes (192 bits)
/// Cipher Mode
/// IV of exactly 8 bytes or null for ECB mode
/// 0 if successful or non-zero error code
/// fileOut and fileIn must not be the same
/// Two overloads: one for byte parameters, one for hex
public int FileEncrypt(String fileOut, String fileIn, ubyte[] key, Mode mode, ubyte[] iv)
{
String strMode = ModeString(mode);
return TDEA_File(fileOut, fileIn, key, cast(int)Direction.Encrypt, strMode, iv);
}
///
/// Decrypt a file
///
/// Name of output file to be created or overwritten
/// Name of input file
/// Key of exactly 8 bytes (64 bits)
/// Cipher Mode
/// IV of exactly 8 bytes or null for ECB mode
/// 0 if successful or non-zero error code
/// fileOut and fileIn must not be the same
/// Two overloads: one for byte parameters, one for hex
public int FileDecrypt(String fileOut, String fileIn, ubyte[] key, Mode mode, ubyte[] iv)
{
String strMode = ModeString(mode);
return TDEA_File(fileOut, fileIn, key, cast(int)Direction.Decrypt, strMode, iv);
}
///
/// Encrypt a file passing key and IV as hex Strings
///
/// Name of output file to be created or overwritten
/// Name of input file
/// Hex-encoded key of exact length
/// Cipher Mode
/// Hex-encoded IV or "" for ECB mode
/// 0 if successful or non-zero error code
/// fileOut and fileIn must not be the same.
/// The output file is in binary format.
public int FileEncrypt(String fileOut, String fileIn, String keyHex, Mode mode, String ivHex)
{
String strMode = ModeString(mode);
return TDEA_File(fileOut, fileIn, cnv.FromHex(keyHex), cast(int)Direction.Encrypt, strMode, cnv.FromHex(ivHex));
}
///
/// Decrypt a file passing key and IV as hex Strings
///
/// Name of output file to be created or overwritten
/// Name of input file
/// Hex-encoded key of exact length
/// Cipher Mode
/// Hex-encoded IV or "" for ECB mode
/// 0 if successful or non-zero error code
/// fileOut and fileIn must not be the same.
/// The output file is in binary format.
public int FileDecrypt(String fileOut, String fileIn, String keyHex,
Mode mode, String ivHex)
{
String strMode = ModeString(mode);
return TDEA_File(fileOut, fileIn, cnv.FromHex(keyHex), cast(int)Direction.Decrypt, strMode, cnv.FromHex(ivHex));
}
}
///
/// Message Digest Hash Functions
///
public class Hash
{
public this(){} // Static methods only, so hide constructor.
private const int HASH_MODE_TEXT = 0x10000;
/* MESSAGE DIGEST HASH FUNCTIONS */
///
/// Creates hash digest of byte input in byte format
///
///
///
///
public ubyte[] BytesFromBytes(ubyte[] message, HashAlgorithm hashAlg)
{
ubyte[] digest;
digest.length = cast(int)Max.PKI_MAX_HASH_BYTES;
HASH_Bytes(digest, digest.length, message, message.length, cast(int)hashAlg);
return digest;
}
///
/// Creates hash digest of byte input in hex format
///
///
///
///
public String HexFromBytes(ubyte[] message, HashAlgorithm hashAlg)
{
String sb;
sb.length = cast(int)Max.PKI_MAX_HASH_LEN;
HASH_HexFromBytes(sb, sb.length, message, message.length, cast(int)hashAlg);
sb = .toString(sb);
return sb;
}
///
/// Creates hash digest of String input in hex format
///
///
///
///
public String HexFromString(String message, HashAlgorithm hashAlg)
{
String sb;
sb.length = cast(int)Max.PKI_MAX_HASH_LEN;
//ubyte[] b = System.Text.Encoding.Default.GetBytes(message);
HASH_HexFromBytes(sb, sb.length, message, message.length, cast(int)hashAlg);
sb = .toString(sb);
return sb;
}
///
/// Creates hash digest of a binary file
///
///
///
/// Message digest in byte format
public ubyte[] BytesFromFile(String fileName, HashAlgorithm hashAlg)
{
ubyte[] digest;
digest.length = cast(int)Max.PKI_MAX_HASH_BYTES;
HASH_File(digest, digest.length, fileName, cast(int)hashAlg);
return digest;
}
///
/// Creates hash digest in hex format of a binary file
///
///
///
/// Message digest in hex format
public String HexFromFile(String fileName, HashAlgorithm hashAlg)
{
String sb;
sb.length = cast(int)Max.PKI_MAX_HASH_LEN;
HASH_HexFromFile(sb, sb.length, fileName, cast(int)hashAlg);
sb = .toString(sb);
return sb;
}
///
/// Creates hash digest in hex format of a text file, treating CR-LF pairs as a single LF
///
///
///
/// Message digest in hex format
public String HexFromTextFile(String fileName, HashAlgorithm hashAlg)
{
String sb;
sb.length = cast(int)Max.PKI_MAX_HASH_LEN;
HASH_HexFromFile(sb, sb.length, fileName, cast(int)hashAlg | HASH_MODE_TEXT);
sb = .toString(sb);
return sb;
}
}
///
/// Data Wiping Functions
///
public class Wipe
{
public this(){} // Static methods only, so hide constructor.
/* MISC UTILITIES */
// NB You can't use this to wipe a C# String.
///
/// Securely wipes and deletes a file using 7-pass DOD standards
///
/// Name of file to be wiped
/// true if successful; false if fails
public bool File(String fileName)
{
int r = WIPE_File(fileName, 0);
return (r == 0);
}
///
/// Zeroises data in memory
///
/// data to be wiped
/// true if successful; false if fails
public bool Data(ubyte[] data)
{
int r = WIPE_Data(data, data.length);
return (r == 0);
}
///
/// Zeroises a String
///
/// String to be wiped
/// true if successful; false if fails
/// NB You can't wipe an ordinary String as they are immutable in C#
public bool WIPE_String(String sb)
{
int r = WIPE_Data(sb, sb.length);
return (r == 0);
}
}
///
/// Random Number Generator to ANSI X9.17/X9.31
///
public class Rng
{
public this(){} // Static methods only, so hide constructor.
///
/// Generates an array of random bytes
///
/// Required number
/// Array of bytes
public ubyte[] Bytes(int numBytes)
{
ubyte[] b;
b.length = numBytes;
RNG_Bytes(b, b.length, "", 0);
return b;
}
///
/// Generates a single random octet (byte)
///
/// Single byte value
public byte Octet()
{
ubyte[] b;
b.length = 1;
RNG_Bytes(b, b.length, "", 0);
return b[0];
}
///
/// Generates a random number (integer) in a given range
///
/// lower value of range
/// upper value of range
/// Random integer
public int Number(int lower, int upper)
{
return RNG_Number(lower, upper);
}
}
///
/// Password Dialog Functions
///
public class Pwd
{
public this(){} // Static methods only, so hide constructor.
///
/// Opens a dialog box to receive a password
///
/// Maximum characters expected in password
/// Caption for dialog window
/// String containing password or Empty String if user cancels
/// Opens a dialog box to receive a password.
public String Prompt(int maxChars, String caption)
{
String sb;
sb.length = maxChars;
int r = PWD_Prompt(sb, sb.length, caption);
if (r < 0)
return null;
sb = .toString(sb);
return sb;
}
///
/// Opens a dialog box to receive a password
///
/// Maximum characters expected in password
/// Caption for dialog window
/// Wording for prompt
/// String containing password or Empty String if user cancels
public String Prompt(int maxChars, String caption, String prompt)
{
String sb;
sb.length = maxChars;
int r = PWD_PromptEx(sb, sb.length, caption, prompt, 0);
if (r < 0)
return null;
sb = .toString(sb);
return sb;
}
}