Function List X-refs Method List Error Codes References Index
CryptoSysTM PKI Pro is an interface to public key cryptography functions and associated cryptography utilities for Visual Basic, C/C++ and C# programmers on Windows systems. It provides strong crypto using established non-patented technology to international standards.
You can create and read secure cryptographic messages encrypted or signed using RSA public key encryption. The results can be used in XML documents using the XML-DSIG and XML-ENC specifications.
You can create and read enveloped-data (encrypted), signed-data and compressed-data Cryptographic Message Syntax (CMS, PKCS#7) objects, which you can wrap in S/MIME entities and use in S/MIME email messages. You can verify the digital signature in a signed-data CMS object; generate and manage RSA public and private keys; carry out "raw" RSA encryption and decryption, and create, read and manage X.509 certificate files and CRLs.
You can create signatures using ECDSA with elliptic curves over primes. You can create new keys and read existing curves in the standard formats.
Other utilities included in the toolkit are the ability to generate message digest hash values using SHA-1, SHA-2, SHA-3, RIPEMD-160, MD5, MD2; generate HMAC keyed-hash message authentication values, wipe files using 7-pass DOD standards, generate cryptographically-secure random numbers to the strict NIST SP800-90 standard, prompt for a password, and convert to and from base64- and hexadecimal-encoded formats.
Public Key Infrastructure (PKI) is defined in [PKIX-MAP] as
The set of hardware, software, people, policies and procedures needed to create, manage, store, distribute, and revoke Public Key Certificates based on public-key cryptography.
The CryptoSys PKI Pro toolkit provides programmers and developers with most of the useful algorithms you need to create the software for a true PKI. We have appropriated a well-known three-letter-acronym. CryptoSys PKI Pro is a sharp tool. It's up to you to manage the hardware, people, policies, procedures and the overall software security you require.
You might also find an alternative definition of PKI from the Devil's Infosec Dictionary [DEVIL] both amusing and relevant.
A system designed to transfer all of the complexities of strong authentication onto end users.
We have used S/MIME Version 3 Message Specification [SMIME-MSG], and Cryptographic Message Syntax (CMS) [CMS] together with the relevant PKCS documents as our primary reference documents. CMS is a stricter subset of PKCS#7 [PKCS7] and is compatible with it.
The CMS (PKCS#7) objects produced by this toolkit should be readable by S/MIME-compatible email clients like Thunderbird if they are wrapped in MIME-conformant email messages. You need to use your own separate program to create, send and read MIME email messages. You can create most of the cryptographic elements required in the [XML-DSIG] and [XML-ENC] specifications to insert into XML documents, but there are no explicit XML processing facilities. The X.509 certificate tools should be compatible with typical certificates issued by Verisign and Thawte. The certificate signing requests (CSRs) it creates are accepted by Verisign's test facility, provided you include the distinguished name attributes they require. As of [v12.0] there is actually a facility to add an MPEG video of you playing with your cat into an X.509 certificate, should you wish.
To get started, read the section on Installation and the section on your programming language:
and if you are a Visual Basic user, please read Visual Basic or Visual Basic: VB6 vs VB.NET.
Then try one of the 'Hello world' programs to make sure it works.
For more details, please read General Programming Issues and the sample code files in the distribution
(these should be in
C:\Program Files\CryptoSysPKI or C:\Program Files (x86)\CryptoSysPKI).
There is more example code on our web site.
Changes in Version 23.0 (September 2024):
kemRSA using KEMRecipientInfo.
See CMS_MakeEnvData with option PKI_KEM_RSA
and RSA-KEM.
subjectKeyIdentifier in CMS signed-data and enveloped-data objects.
See option PKI_USE_SKI.
kemParamsukmHASsubjectKeyIdentifierrecipientIdentifierCountOfDigestAlgscertificate/NHASsubjectKeyIdentifiersignerIdentifierChanges in Version 22.1 (1 January 2024):
Changes in Version 22.0 (23 October 2023):
ECC_MakeKeys.
SIG_SignData, CMS signed-data objects using
CMS_MakeSigData,
and for signing X509 certificates using
X509_MakeCert.
ECC_DHSharedSecret,
and an X448 key can be included in an X.509 certificate using
X509_MakeCert.
CIPHER_EncryptAEAD
and in creating a CMS AuthEnvelopedData object using
CMS_MakeEnvData.
HPKE_LabeledExtract,
HPKE_LabeledExpand and
HPKE_DerivePrivateKey.
See Hybrid Public Key Encryption (HPKE).
PBE_Scrypt and
PBE_ScryptHex
and their equivalent .NET Pbe Class methods.
ECC_SaveKey so as to always save private EC keys with the equivalent public key included.
"PKCS8 ONE ASYMMETRIC KEY" to
ASN1_Type
when detecting a PKCS#8 v2 OneAsymmetricKey private key object.
PFX_MakeFile (like P12 files used by SET in Paraguay).
ASN1_TextDump
to display the object lengths more clearly.
Changes in Version 21.0.11 (11 June 2023):
X509_ReadCertStringFromPFX to read "double-encrypted" P12/PFX file as issued by CAs in Paraguay.
Changes in Version 21.0 (1 January 2023):
XOF_Bytes and equivalent .NET method Xof.Bytes
to provide eXtendable-Output Functions of any length using SHAKE128 and SHAKE256 as per [FIPS202]
and MGF1-SHA-* as per [PKCS#1].
PRF_Bytes and equivalent .NET method Prf.Bytes
to produce pseudorandom output of any length using KMAC128 and KMAC256 as per NIST SP800-185 [SP800-185].
CIPHER_FileEncrypt
and CIPHER_FileDecrypt
(.NET: Cipher.FileEncrypt Method,
Cipher.FileDecrypt Method).
Use this option to encrypt and decrypt files using AES-GCM.
CIPHER_EncryptBytes,
CIPHER_DecryptBytes,
CIPHER_EncryptHex and
CIPHER_DecryptHex.
CIPHER_FileEncrypt to prevent input file being
accidentally overwritten.CNV_ShortPathName to help handle filenames with "International" characters.
See Filenames with "International" characters.
PKI_FormatErrorMessage to return a formatted error message string for the last error.
RSA_ReadAnyPublicKey
(.NET Rsa.ReadPublicKey Method).
initials,
generationQualifier,
dnQualifier and
pseudonym.
These complete the list of "SHOULD support" standard attribute types in section 4.1.2.4 of [RFC5280].
cRLDistributionPoints extension to the X.509 Extensions Parameter.
Changes in Version 20.6 (10 September 2022):
CMS_MakeEnvData
(.NET: Cms.MakeEnvData Method).
Changes in Version 20.5 (18 July 2022):
CMS_MakeEnvData[FromBytes][FromString]
(.NET: Cms.MakeEnvData Method)
CMS_MakeEnvData[FromBytes][FromString].
smimeCapabilities extension to an X.509 certificate. See X.509 Extensions Parameter.
Changes in Version 20.4 (24 April 2022):
brainpoolP256r1, brainpoolP384r1, and brainpoolP512r1.
These ECC curves are supported in X.509 certificates and CMS SignedData objects,
as well as in the standard ECC key generation and management and signature functions using ECDSA.
RSA_ReadAnyPrivateKey,
RSA_ReadAnyPublicKey,
ECC_ReadPrivateKey, and
ECC_ReadPublicKey.
This is an advanced option to turn off encryption security for internal keys and allow the key strings to be used between separate processes.
Do not use unless you know what you are doing. It is not available in .NET or C++ (STL) interfaces.
Changes in Version 20.3 (8 January 2022):
std::string and std::vector objects.
RSA_MakeKeysXtd and RSA_SaveEncKey
which simplify the parameters and options when saving encrypted keys.CNV_Utf8FromWide which maps a UTF-16 (wide character) string to a UTF-8-encoded string.
This is specifically for C and C++ programmers using wide (wchar_t) characters and strings.
X509.OutputOpts.UTF8String with X509.OutputOpts.Unicode.
This option will output a distinguished name in Unicode character set (UTF-8 or UTF-16 as appropriate).
X509.TextDump where LDAP option was ignored.Changes in Version 20.2 (3 October 2021):
basCrPKI.bas.
The old files basCrPKI64.bas, basCrPKI64_32.bas and basCrPKIWrappers.bas
are no longer needed and indeed must not be used. See Using with Classic Visual Basic VB6 and VBA.
Cms.QuerySigData Method)
to extract information from CMS signed-data objects,
namely signatureValue, DigestOfSignedAttrs, DigestOfeContent and signingCertHash.
Cms.MakeSigData Method
with the Cms.SigDataOptions.PseudoSig option,
and the Cms.MakeSigDataFromPseudo Method.
CIPHER_EncryptBytes and
CIPHER_DecryptBytes
to replace deprecated
CIPHER_EncryptBytes2 and
CIPHER_DecryptBytes2.
This has no effect on .NET methods or the VBA wrapper functions (it just gets rid of that "2").
Mid function does for a string.
Changes in Version 20.1 (13 March 2021):
Changes in Version 20.0 (17 October 2020):
Ecc.DHSharedSecret Method.
Cipher.Encrypt Method
and Cipher.Decrypt Method).
Rsa.FromXMLString method) to read XML data with prefixes.
keyUsage=noncritical to force keyUsage attributes in a new X.509 certificate to be non-critical.
SigAlgorithm option
together with specific X509.CertOptions,
X509.CrlOptions or
X509.CsrOptions).
Changes in Version 12.4 (12 May 2020):
Cms.MakeSigData Method).
See Additional Security Attributes.
Cms.SigDataOptions.AddSigningCertificate) to add an ESS Signing Certificate to the signed attributes.Cms.SigDataOptions.AddAlgProtection) to add an Algorithm Protection Attribute [RFC6211] to the signed attributes.Cms.VerifySigData) to carry out additional validation when
signed attributes in a CMS signed-data object contain an ESS Signing Certificate or Algorithm Protection Attribute.
HASsigningCertificate and HASalgorithmProtection
to CMS_QuerySigData (Cms.QuerySigData).
PKI_ModuleInfo
(.NET General.ModuleInfo Method)
to show additional information about the core DLL module, e.g. "Licensed Developer Edition".
Changes in Version 12.3 (6 March 2020):
RNG_Guid
(.NET Rng.Guid Method)
to generate a random 36-character Global Unique IDentifier (GUID) string.
X509.MakeCert Method
and
X509.CertRequest Method)
to do the following:
extKeyUsage extension purposes in the X.509 Extensions Parameter,
with an option to mark the extension critical.pbeWithSHAAnd3-KeyTripleDES-CBC algorithm
(.NET X509.ReadCertStringFromPFX Method
and
X509.GetCertFromPFX Method).
pbeWithSHAAnd3-KeyTripleDES-CBC.
(.NET StrongCert option for the Pfx.MakeFile Method).
PrefixIV option for
Cipher.Encrypt Method
and
Cipher.Decrypt Method).
Changes in Version 12.2 (24 March 2019):
RSA_ReadAnyPrivateKey and
RSA_ReadAnyPublicKey
(.NET Rsa.ReadPrivateKey Method
and Rsa.ReadPublicKey Method).
The key may be provided either in a JSON file or as a JSON string. No password is required.
See the example in RSA_ReadAnyPublicKey.
CMS_ReadSigData and its string/byte variants now read content from any CMSVersion (previously only version 1).CMS_MakeSigData
and CMS_MakeEnvData to accept lists of X.509 certificates in a PKCS#7 certificate chain file (.p7c/.p7b).
Cms.ReadOptions for
Cms.ReadSigDataToFile Method and
Cms.ReadEnvDataToFile Method.
This allows the use of the BigFile option when reading large CMS files.
Cms.Options Enumeration.
X509_GetCertCountInP7Chain
(.NET Cms.GetCertCountInP7Chain Method)
as a cleaner function to help in extracting X.509 certificates from a PKCS#7 certificate chain file.
Changes in Version 12.1 (17 November 2018):
CIPHER_EncryptAEAD and CIPHER_DecryptAEAD
(.NET Cipher.EncryptAEAD Method and
Cipher.DecryptAEAD Method).
X509_ReadCertStringFromPFX
(.NET X509.ReadCertStringFromPFX Method)
to extract X.509 certificate details directly from PFX/PKCS12 data into memory.
X509_ReadCertStringFromP7Chain
(.NET X509.ReadCertStringFromP7Chain Method)
to extract X.509 certificate details directly from P7 certificate chain data into memory.
CMS_ReadEnvData and CMS_ReadEnvDataToString
(.NET Cms.ReadEnvDataToFile Method and
Cms.ReadEnvDataToString Method).
ASN1_TextDump to catch obscure error when parsing random octet strings.
CIPHER_Bytes function. Use safer functions
CIPHER_EncryptBytes2 and CIPHER_DecryptBytes2 instead.
(No effect for .NET methods.)
CIPHER_EncryptBytes2 and CIPHER_DecryptBytes2
to handle NULL and zero-length inputs more consistently.
Changes in Version 12.0 (20 June 2018):
X509_MakeCert
(.NET
X509.MakeCert Method).
X509_MakeCRL,
(.NET
X509.MakeCRL Method).
X509_CertRequest
(.NET
X509.CertRequest Method).
X509_VerifyCert
(.NET
X509.VerifyCert Method).
X509_ValidatePath
(.NET
X509.ValidatePath Method).
CMS_MakeSigData and CMS_VerifySigData
(.NET
Cms.MakeSigData Method,
Cms.VerifySigData Method).
CMS_MakeEnvData and CMS_ReadEnvData
(.NET
Cms.MakeEnvData Method,
Cms.ReadEnvDataToFile Method).
RSA_Encrypt and RSA_Decrypt
(.NET Rsa.Encrypt Method and
Rsa.Decrypt Method)
to encrypt and decrypt short messages using
the RSA encryption schemes from PKCS#1, including RSAES-OAEP.
ECC_ReadPublicKey
(.NET Ecc.ReadPublicKey Method).
X509_MakeCert and X509_CertRequest
(.NET X509.MakeCert Method,
X509.CertRequest Method).
X509_VerifyCert
(.NET
X509.VerifyCert Method).
\<hex><hex>) to insert 8-bit octets in an attribute value,
see Specifying Distinguished Names.
X509_MakeCert
(.NET X509.MakeCert Method).
See Add an arbitrary X.509 Extension. This allows you, for example, to add a video of your cat to an X.509 certificate :-).
X509_QueryCert (useful for checking the parameters of RSA-PSS signatures).COMPR_Compress and COMPR_Uncompress functions
to compress and uncompress data using zlib compression
(.NET Compr.Compress Method
and Compr.Uncompress Method).
WIPE_File
(.NET Wipe.File Method),
and added option to overwrite with a single pass of zero bytes (quicker but less secure).X509_TextDumpToString function
(.NET X509.TextDumpToString Method)
to dump details of X.509 certificate (or a CRL or a PKCS#10 CSR) directly to a string.
ASN1_TextDumpToString function
(.NET Asn1.TextDumpToString Method)
to dump details of ASN.1 formatted data directly to a string.
X509_VerifyCert, X509_ValidatePath,
X509_CheckCertInCRL, and X509_CertIsValidNow with consistent error codes.
All these functions now return 0 on success (as before) or a specific nonzero error code on failure.
More details of any error can usually be found using PKI_LastError.
X509.Options Enumeration.CIPHER_EncryptBytesPad and CIPHER_DecryptBytesPad. Use instead
CIPHER_EncryptBytes2 and
CIPHER_DecryptBytes2.
This has no effect on .NET methods.
Pfx.MakeFile with obsolete Boolean parameter. diCrPKI.h and the public constants in basCrPKI.bas.
This is important if you have written an interface that hardcodes the option values. If you use the defined C macros or public VBA constants, it should not be an issue.
Changes in Version 11.2 (8 August 2017):
ECC_MakeKeys and ECC_SaveEncKey so "prf" option works in szParams parameter, e.g. "prf=hmacWithSHA256;".RSA_ToXMLStringEx function
(.NET Rsa.ToXMLString Method)
which allows adding namespace prefix before element names, e.g. <ds:RSAKeyValue>.
ECC_KeyHashCode function
(.NET Ecc.KeyHashCode Method)
to give a 32-bit hash value for an ECC private or public key.PKI_Platform function
(.NET General.Platform Method)
to give operating platform "Win32" or "X64" directly.X509_TextDump to display distinguished name in LDAP form and serial number in decimal.ASN1_TextDump and ASN1_Type now accept a plain base64 text file as input.Changes in Version 11.1 (20 May 2016):
CIPHER_EncryptBytes2 and
CIPHER_DecryptBytes2
as safer replacements for
CIPHER_EncryptBytesPad and
CIPHER_DecryptBytesPad (since withdrawn in v12.0)
with explicit checks for lengths of key and IV byte arrays.
These new safer functions are now used internally in the equivalent .NET Cipher class methods.
CIPHER_FileEncrypt and
CIPHER_FileDecrypt
as safer replacements for the now-deprecated
CIPHER_File
with explicit checks for lengths of key and IV byte arrays.
In addition, these new functions allow the user to specify the type of padding used for ECB and CBC modes
(previously only PKCS5Padding),
and give the option to prepend the IV to the ciphertext data.
Cipher.BlockBytes Method
and
Cipher.KeyBytes Method
to return the correct sizes in bytes of the cipher block and key for a given block cipher algorithm.
CNV_BytesFromHexStr and
CNV_BytesFromB64Str
to be stricter and return an error if any obviously invalid characters are found (formerly they were just ignored).
Whitespace characters are still allowed in both hex and base64 strings, and ASCII punctuation characters in a hex string.
So, for example, the hex string "DE:AD:BE:EF" is still OK,
but characters in the range [G-Zg-z] in a hex string now cause an error.
PFX_VerifySig.OCSP_MakeRequest.
Space characters and an odd number of hex digits are now accepted correctly.
Changes in Version 11.0 (8 March 2016):
secp256k1.SIG functions
and Sig class methods.
CNV_ReverseBytes. For .NET
Cnv.ReverseBytes
CNV_NumFromBytes and CNV_NumToBytes. For .NET
Cnv.NumFromBytes and Cnv.NumToBytes
CNV_Base58FromBytes and CNV_Base58ToBytes. For .NET
Cnv.ToBase58 and Cnv.FromBase58
HASH(HASH(m))),
and the Bitcoin160 algorithm (RIPEMD160(SHA256(m))).
X509_CertRequest.
serialNumber as a decimal integer when using the X.509 Extension Parameter.
X509_MakeCert so when importing from an existing certificate signing request (CSR) it will copy
the exact distinguished name and any keyUsage or subjectAltName extensions in the CSR file.
ASN1_TextDump and X509_TextDump
to display more information about unexpected ASN.1 objects (i.e., to display the ASN.1 value in hex instead of ignoring it).
Cnv.CheckUTF8 Method (String).
See Deprecated and obsolete UTF-8 functions.
Changes in Version 10.0 (27 March 2015):
RSA_ReadAnyPrivateKey
and RSA_ReadAnyPublicKey
to read private and public keys from almost "any" supported format into an internal key string.
SIG_SignData
and SIG_SignFile
to create RSA signatures in one step.
The output is a base64-encoded string suitable for
a <SignatureValue> node in an XML-DSIG document.
SIG_VerifyData
and SIG_VerifyFile
to verify RSA signatures in base64-encoded form.
RSA_KeyValue to extract a base64-encoded RSA key value from
an internal key string.
The output is a base64-encoded string suitable for a <RSAKeyValue> node in an XML-DSIG document.
CMS_MakeComprData
and CMS_ReadComprData
to create and read CMS compressed-data (.p7z) files.
SMIME_Wrap
and Smime.Wrap method
to create an S/MIME file from binary CMS signed-data, enveloped-data and compressed-data objects.
SMIME_Extract
and Smime.Extract method
to extract the body from an S/MIME file.
SMIME_Query
and Smime.Query method
to query an S/MIME file for header information.
ASN1_TextDump
and ASN1_Type to analyze and check the type of ASN.1 objects.
The corresponding .NET methods are
Asn1.TextDump Method
and Asn1.Type Method.
X509_MakeCert, X509_MakeCertSelf
and X509_CertRequest functions.
See X.509 Extensions Parameter.
X509_GetCertFromPFX function
or new X509.GetP7ChainFromPFX method.
PKI_CMS_BIGFILE option to the CMS_MakeSigData,
CMS_ReadSigData and CMS_VerifySigData functions
to process large signed-data files more efficiently.
Cms.QueryEnvData Method (String, String, Boolean) Cms.QuerySigData Method (String, String, Boolean) Cms.GetSigDataDigest Method (String, String, Boolean) Cms.ReadSigDataToFile Method (String, String, Boolean) Cms.ReadSigDataToString Method (String, Boolean) Cms.VerifySigData Method (String, String, String, Boolean)
Changes in Version 3.10 (2 September 2014):
CIPHER_EncryptBytesPad
and CIPHER_DecryptBytesPad which use the specified block cipher algorithm,
mode and padding to encrypt and decrypt data in a byte array. Padding is added if required before encryption and removed after decryption.
The equivalent .NET methods are
Cipher.Encrypt Method and
Cipher.Decrypt Method
PAD_* functions
and
Cipher.Pad
and
Cipher.Unpad methods.
PBE_Kdf2
and PBE_Kdf2Hex to derive a key of any length from a password using the PBKDF2 algorithm
from PKCS#5.
The equivalent .NET methods are
Pbe.Kdf2 and
Pbe.Kdf2 (Int32, String, String, Int32).
Cms.MakeEnvData Method
(String, String, String, CipherAlgorithm, Cms.EnvDataOptions)
and
Cms.MakeEnvDataFromString Method
(String, String, String, CipherAlgorithm, Cms.EnvDataOptions)
to simplify using AES as the content encryption algorithm.
PKI_Version to return a five-digit number of the form
Major * 10000 + Minor * 100 + Release. For example, version 3.10.1 will return the number 31001
whereas version 3.9.4 would have returned 394.
Changes in Versions 3.9.1 to 3.9.4 (4 October 2012 to 9 October 2013):
RNG_Initialize
to always create a new seed file, even if one does not exist
(the previous behaviour was to fail with an error if the seed file did not exist).
PKI_X509_DECIMAL option in
X509_CertSerialNumber and
X509_QueryCert.
rc2CBC mode in CMS_ReadEnvData.
Changes in Version 3.9 (8 September 2012):
PKI_X509_LDAP to the functions
X509_CertIssuerName,
X509_CertSubjectName and
X509_QueryCert
to display the distinguished name in LDAP string form as per [RFC4514].
This is intended to help users who wish to create an <X509IssuerName> or <X509SubjectName> element
within an <X509Data> in an XML-DSIG document.
For more details see LDAP String Representation of Distinguished Names.
PKI_X509_DECIMAL to the functions
X509_CertSerialNumber and
X509_QueryCert
to display the serial number in decimal form instead of hexadecimal.
Use to create an <X509SerialNumber> element in XML-DSIG.
STREET, UID, GN and TITLE to supported attribute types
when specifying a distinguished name for an X.509 certificate.
encryptedContent,
iv and encryptedKey
to CMS_QueryEnvData.
X509_MakeCert[Self].
RSA_EncodeMsg in PKI_EMSIG_PKCSV1_5 mode.Changes in Version 3.8 (14 January 2012):
PFX_MakeFile so it now creates PFX files in the exact format that OpenSSL creates
with weak 40-bit encryption of the certificate as default behaviour.
RSA_ReadPrivateKeyFromPFX function to read a private key directly from
a PFX file into an internal key string.
Note that this is different from the existing RSA_GetPrivateKeyFromPFX function which
just extracts the encrypted PKCS-8 file and saves it. We try to use the convention "Read" to mean read-into-internal-string
and "Get" to mean extract-and-save-as-a-file.
X509_GetCertFromPFX to cope with encrypted certificates.
RSA_PublicKeyFromPrivate function to convert an internal private key string
into a public one. This is useful if you only have a private key file like a PFX file.
Changes in Version 3.7 (1 July 2011):
CNV_CheckUTF8File to check if a file
contains valid UTF-8 characters.
PKI_CMS_BIGFILE option to the CMS_MakeEnvData
and CMS_ReadEnvData to process large enveloped-data files more efficiently.
This option allows, in theory, files of unlimited length to be enveloped.
In addition, the 16 MB limit on the usual mode has been removed.
CMS_MakeEnvData function
to fail if any of the specified certificate files are missing or corrupted.
CMS_MakeEnvData[FromString].
PKI_CMS_FORMAT_BASE64/inputIsBase64 option in
functions that read base64-encoded CMS files like
CMS_ReadEnvData,
CMS_ReadSigData,
CMS_QueryEnvData and
CMS_QuerySigData.
These functions (and their .NET equivalents) will now detect the encoding of the input file automatically.
Cms.SigDataOptions enumeration to provide advanced options and
complement the Cms.EnvDataOptions enumeration.
CMS_MakeEnvData and
CMS_MakeSigData
were meant to use SHA-2 but didn't.
RSA_MakeKeys and RSA_SavePublicKey.
The file is now saved in the exact same format as OpenSSL; i.e. "Unix" line endings and a line-length of 64 characters.
This is specifically to help users in Portugal with
the peculiar standards enforced by the DGCI (and should not make any difference to other users).
Changes in Version 3.6 (25 August 2010):
PAD_BytesBlock and
PAD_HexBlock
to provide PKCS#5/#7 padding to encryption blocks and the equivalent functions to remove the padding,
PAD_UnpadBytes and
PAD_UnpadHex.
The corresponding .NET methods are
Cipher.Pad and
Cipher.Unpad.
CNV_Latin1FromUTF8Bytes and
CNV_UTF8BytesFromLatin1
to handle UTF-8 encoded data correctly using byte arrays instead of strings.
These replace the deprecated functions
CNV_Latin1FromUTF8 and
CNV_UTF8FromLatin1.
CNV_CheckUTF8Bytes, and the corresponding method
Cnv.CheckUTF8(Byte[]) to replace the deprecated CNV_CheckUTF8
and Cnv.CheckUTF8(String).
See also UTF-8 and Latin-1.
CNV_ByteEncoding and equivalent method
Cnv.ByteEncoding to convert encoding in a byte array between UTF-8 and Latin-1.
Changes in version 3.5 (2 May 2010):
X509_MakeCRL function to make a basic X.509 certificate revocation list (CRL).
X509_CheckCertInCRL function to check if a given X.509 certificate
has been revoked in an X.509 certificate revocation list (CRL).
OCSP_MakeRequest function to
create an Online Certification Status Protocol (OCSP) request as a base64 string.
OCSP_ReadResponse function to
read a response to an Online Certification Status Protocol (OCSP) request and output the main results in text form.
X509_TextDump function to dump details of X.509 certificate (or a CRL or a PKCS10 CSR) to a text file.
X509_ValidatePath function to validate a certificate path, either in the form of
a list of X.509 certificate filenames or in a PKCS7 "certs-only" certificate chain file (.p7b or .p7c).
X509_MakeCert function
to allow the creation of a new X.509 certificate using a PKCS#10 Certificate Signing Request (CSR).
X509_VerifyCert function
to also verify X.509 Certificate Revocation List (CRL) and PKCS#10 Certificate Signing Request (CSR) documents.
X509_QueryCert function.
CMS_ReadEnvData[ToString] and
CMS_ReadSigData[ToString]
functions, allowing the user to pass the data directly as a base64 string or PEM string;
and added the automatic detection of format for input files.
Changes in version 3.4 (19 December 2009):
Changes in version 3.3 (19 February 2009):
X509_MakeCert and
X509MakeCertSelf functions,
and added more options for distinguished names.
PEM_FileFromBinFile and
PEM_FileToBinFile
functions to enable you to convert files between ASN.1 DER/BER binary format and PEM format.
WIPE_File function
- up to three times faster for large files.
RSA_FromXMLString
function to allow the import of a restricted RSA private key from XML data consisting only of the
<Modulus>, <Exponent> and <D> fields.
The resulting "internal" key string can be used to sign raw data but cannot be saved in a private key file.
This is useful to reproduce certain test vectors.
PKI_EMSIG_ISO9796 option to the RSA_EncodeMsg and
RSA_DecodeMsg
functions to enable the user to encode and decode a message according to ISO/IEC 9796-1.
RSA_RawPrivate and
RSA_RawPublic
functions to sign and decrypt RSA signatures using the "RSA2" method used in ISO/IEC 9796-1, ANSI X9.31 and P1363.
PKI_KEYGEN_INDICATE option in RSA_MakeKeys()
so it does not clash with the des-EDE3-CBC block cipher option.
Changes in version 3.2 (2 February 2008):
CIPHER_Bytes,
CIPHER_Hex, and
CIPHER_File.
HASH_HexFromHex
and HMAC_HexFromHex functions.
"shaXXXWithRSAEncryption"
with SHA-224/256/384/512
for
X509_MakeCert[Self]
and
X509_CertRequest.
CMS_MakeSigData[FromString].
CMS_MakeEnvData[FromString].
RSA_KemWrap and
RSA_KemUnwrap which will wrap (encrypt) and unwrap (decrypt)
secret keying data for a recipient with the recipient's RSA key using the
RSA-KEM ("Simple RSA") algorithm.
[Withdrawn in v3.4].
CIPHER_KeyWrap
and CIPHER_KeyUnwrap
using AES-wrap and Triple DES wrap.
RSA_SaveEncPrivateKey and
RSA_ReadEncPrivateKey
functions.
CMS_QueryEnvData function,
and included the ability to pass a base64- or PEM-encoded certificate list to
CMS_MakeEnvData and
CMS_MakeSigData.
Changes in version 3.1 (2 August 2007):
X509_MakeCert or X509_MakeCertSelf.
See Specifying Distinguished Names for more details.
RSA_KeyMatch
function to verify that a pair of RSA private and public key strings are matched.
TDEA_File.
To prevent accidental misuse, if an error occurs when using this function, the output file will now not exist.
CMS_MakeEnvData function to conform with the
PKI requirements of the German Health System.
Changes in version 3.0 (27 March 2007):
RSA_KeyHashCode
function to allow comparison of internal key strings.
HASH functions.HMAC functions to compute a keyed hash value,
HMAC_HexFromBytes and
HMAC_Bytes.
X509_KeyUsageFlags and
X509_QueryCert.
X509_ReadStringFromFile and
X509_SaveFileFromString.
Changes in version 2.9 (12 August 2006):
CMS_MakeSigDataFromSigValue
function to create a SignedData
object directly from a pre-computed signature value.
CNV_CheckUTF8
function to check whether a string contains only valid UTF-8 characters.TDEA_BytesMode.
RNG_Number function to generate
a random number in a given range.
Changes in version 2.8 (26 April 2006):
X509_GetCertFromP7Chain and
X509_GetCertFromPFX.
CMS_VerifySigData and
CMS_QuerySigData functions.
nMajor and nMinor in
PKI_Version.
Changes in version 2.7 (11 December 2005):
X509_VerifyCert()
can now verify certificates signed using DSA.
RSA_ReadEncPrivateKey()
to read PKCS#8 files encrypted with RC2.
CMS_ReadEnvData()
and
CMS_ReadEnvDataToString()
more tolerant of different input formats, including adding support to read
data encrypted with RC2.RSA_MakeKeys()
and
RSA_SaveEncPrivateKey().
RSA_MakeKeys().
X509_MakeCert()
and
X509_MakeCertSelf()
UTF8String and to decode multi-byte distinguished names
into 8-bit ASCII, if possible.
Classic Visual Basic (VB6/VBA) code is shown shaded as follows:
Dim strData As String Dim nRet As Long strData = "Hello world" Debug.Print strData ' ... etc
Code in C/C++ is shown as:
char *str = "Hello world";
printf("%s\n", str);
Code in VB.NET is shown as:
Dim nDataLen As Integer Dim abData() As Byte If strData.Length = 0 Then Exit Function abData = System.Text.Encoding.Default.GetBytes(strData) nDataLen = abData.Length
Code in C# is shown as:
// Encrypt in CBC mode using hex strings
keyhex = "737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32";
ivhex = "B36B6BFB6231084E";
plain = "5468697320736F6D652073616D706520636F6E74656E742E0808080808080808";
cipher = "d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4";
s = Tdea.Encrypt(plain, keyhex, Mode.CBC, ivhex);
Console.WriteLine("CT={0}",s);
Console.WriteLine("OK={0}",cipher);
Debug.Assert(String.Compare(s, cipher, true)==0, "Tdea.Encrypt{Hex,CBC} failed");
Code in Python is shown as:
>>> from cryptosyspki import * >>> Gen.version() # "hello world!" for CryptoSys PKI 200600 >>> Hash.hex_from_data(b'abc') # compute SHA-1 hash in hex of 'abc' as bytes 'a9993e364706816aba3e25717850c26c9cd0d89d'
Output from code samples is shown as:
Result=OK
All functions called directly in the CryptoSys PKI Pro toolkit begin with 3 or 4 capital letters followed by an underscore "_", e.g.
nRet = RSA_ReadPublicKey(rsaReadPublicKey, nKeyLen, strKeyFile, 0)
For VBA/VB6 users, there are convenient wrapper functions provided in
basCrPKI.bas
which avoid the complications of having to pre-dimension strings, etc. These function names
begin with lowercase letters and no underscore.
For example hmacHexFromBytes and rsaReadPublicKey.
' Test case 1 from RFC 2202 and RFC 4231 ' Data = "Hi There" strDigest = hmacHexFromHex("4869205468657265", "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", PKI_HASH_SHA256) Debug.Print "HMAC-SHA-256=" & strDigest Debug.Print "CORRECT =b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"
Except where otherwise noted, the CryptoSysTM PKI Pro program, its executables, sample source code and this document were written by David Ireland and are copyright (c) 2004-25 by DI Management Services Pty Limited t/a CryptoSys, all rights reserved. They may not be distributed or reproduced separately by any means whatsoever without express permission in writing. Users holding a valid developer's licence are permitted to distribute the executables as part of a value-added application according to the terms of their licence.
The latest version of CryptoSys PKI Pro may be obtained from <https://cryptosys.net/pki/>.
There is no theory explained here. We assume you know what you are doing. For a good introduction to the concepts, try William Stallings, Cryptography and Network Security: Principles and Practice [STAL]. For a more detailed work, see Some Examples of the PKCS Standards by RSA Laboratories [PKCS-EX], an old but still useful guide. If all else fails, try reading the primary references we used.
You are assumed to have a reasonable knowledge of the basics of cryptography and public key encryption, and that you can program in the language of your choice to an advanced standard.
Please note A caution about insecure default algorithms.
"rsaEncryption")."sha1WithRSAEncryption" (RSA-SHA1) (default)"sha224WithRSAEncryption" (RSA-SHA224)"sha256WithRSAEncryption" (RSA-SHA256) [minimum recommended]"sha384WithRSAEncryption" (RSA-SHA384)"sha512WithRSAEncryption" (RSA-SHA512)"md5WithRSAEncryption" (RSA-MD5) [legacy, not recommended for new implementations]"md2WithRSAEncryption" [legacy, definitely not recommended]"rsaPSS" and the RSAES-OAEP encryption scheme with the following hash algorithms:
"sha1" (RSA-PSS-SHA1)"sha224" (RSA-PSS-SHA224)"sha256" (RSA-PSS-SHA256)"sha384" (RSA-PSS-SHA384)"sha512" (RSA-PSS-SHA512)"dsaWithSha1" and
DSA public key "DSAPublicKey" for verifying X.509 certificates and CMS SignedData objects only
(but inherited DSS parameters are not supported).ecdsaWithSHA1 (ECDSA-SHA1)ecdsaWithSHA224 (ECDSA-SHA224)ecdsaWithSHA256 (ECDSA-SHA256) [minimum recommended]ecdsaWithSHA384 (ECDSA-SHA384)ecdsaWithSHA512 (ECDSA-SHA512)P-192, also known as secp192r1 and prime192v1P-224, also known as secp224r1P-256, also known as secp256r1 and prime256v1 [minimum recommended]P-384, also known as secp384r1P-512, also known as secp512r1secp256k1 (the Bitcoin curve) brainpoolP256r1 [RFC5639]brainpoolP384r1 [RFC5639]brainpoolP512r1 [RFC5639]"des-EDE3-CBC" (default)"aes128-CBC" [minimum recommended]"aes192-CBC""aes256-CBC"In addition, the following algorithm can be read by the CMS_ReadEnvData[ToString] functions:
"rc2CBC" with 40-bit or 128-bit effective key sizes"aes128-Wrap" (default)"aes192-Wrap""aes256-Wrap""cms3DESWrap""sha1" or "sha-1" (default)"sha224""sha256" [minimum recommended]"sha384""sha512""md5""md2""ripemd160"We keep MD2 here so we can reproduce the examples from RSA Laboratories' 1993 paper [PKCS-EX] and to do tests with some (very old) X.509 certificates. You are recommended to use at least SHA-256 in new applications.
For generating HMAC message authentication codes with the HMAC_ functions.
"hmacWithSHA1""hmacWithSHA224""hmacWithSHA256" [minimum recommended]"hmacWithSHA384""hmacWithSHA512""hmacWithMD5" [legacy, not recommended for new applications]These algorithms from PKCS#5 and PKCS#12 can be used to create PKCS#8 encrypted private key files:
"pbeWithSHAAnd3-KeyTripleDES-CBC" (default)"pkcs5PBES2" using the pkcs5PBKDF2 key derivation function with encryption algorithms:
"des-EDE3-CBC""aes128-CBC" [minimum recommended]"aes192-CBC""aes256-CBC""pbeWithMD5AndDES-CBC" [legacy, not recommended for new applications]"pbeWithMD2AndDES-CBC" [legacy, not recommended for new applications]"pbeWithSHA1AndDES-CBC" [legacy, not recommended for new applications]In addition to those above, the following legacy algorithms can be read by the RSA_ReadEncPrivateKey function:
"pkcs5PBES2" using pkcs5PBKDF2 with "desCBC""pkcs5PBES2" using pkcs5PBKDF2 with "rc2CBC""pbeWithSHAAnd128BitRC2-CBC""pbeWithSHAAnd40BitRC2-CBC""pbeWithMD5AndRC2-CBC""pbeWithMD2AndRC2-CBC""pbeWithSHA1AndRC2-CBC""EncryptedPrivateKeyInfo" (default for private keys)"RSAPublicKey" (default for public keys)"PrivateKeyInfo""RSAPrivateKey" (OpenSSL private key file format)"SubjectPublicKeyInfo" (OpenSSL public key file format)The above key values can be passed as (a) a binary DER-encoded ASN.1 file, (b) a text file in PEM format, (c) a string containing the key in PEM format.
Also supported are RSA private and public keys represented in XML format to XKMS 2.0 [XKMS] and JSON Web Key (JWK) format [JWK]. For more details, see Key Storage Format.
EncryptedPrivateKeyInfo using "id-ecPublicKey" (default for private keys)PrivateKeyInfoECPrivateKey from [RFC5915]SubjectPublicKeyInfo from [RFC5480] for public keys (default)These elliptic curve key values can be passed as (a) a binary DER-encoded ASN.1 file, (b) a text file in PEM format, (c) a string containing the key in PEM format.
EnvelopedData content type [RFC5652] using key management techniques key transport (ktri),
key agreement (kari), previously distributed symmetric key-encryption keys (kekri), and password-based key management (pwri).
dhSinglePass-stdDH-sha*kdf-scheme aka ecdhX963KDF-SHA* (where * is 1, 256, 384, or 512)dhSinglePass-stdDH-hkdf-sha*-scheme aka ecdhHKDF-SHA* (where * is 256, 384, or 512)RecipientIdentifier field in ktri and kari types both choices issuerAndSerialNumber
and subjectKeyIdentifier are supported.cms3DESwrap and aes*-wrap are supported (where * is 128, 192, or 256).OriginatorInfo and UnprotectedAttrs are not supported.EnvelopedData, RSA-KEM is supported using the KemRecipientInfo structure (informally "kemri")
inside a CMS OtherRecipientInfo (ori),
see RSA-KEM.
AuthEnvelopedData content type [RFC5083] using the same key management types and schemes as for EnvelopedData above
using content-encryption algorithms AES_*_GCM and CHACHA20_POLY1305 (where * is 128, 192, or 256).
SignedData content type [RFC5652].
UnsignedAttributes is not supported.CompressedData content type as per [RFC3274].
Only CMS objects with an id-data inner content type are supported.
These algorithms from [PKIXALG] are not currently supported:
"DHPublicKey")"id-keyExchangeAlgorithm")RSAPublicKey as per PKCS#1 for public keysEncryptedPrivateKeyInfo as per PKCS#8 for private keys.PrivateKeyInfo format for private keys are also supported.PrivateKeyInfo form at your own risk.WIPE_Data to erase them when no longer needed.
RSA_ToXMLString and
RSA_FromXMLString functions to convert back and forth
between XML and the toolkit's internal string format. Be very careful as the XML private key data is not encrypted.
RSA_ReadAnyPrivateKey and
RSA_ReadAnyPublicKey.
(.NET Rsa.ReadPrivateKey Method
and Rsa.ReadPublicKey Method).
The key may be provided either in a JSON file or as a JSON string. No password is required.
SubjectPublicKeyInfo as per [RFC5480] for public keysEncryptedPrivateKeyInfo as per PKCS#8 for private keys.ECC_ReadPublicKey.CAUTION: Many of the default algorithms in this Toolkit (originally written nearly 20 years ago) are no longer considered secure. You are recommended explicitly to use at least the following minimum-strength algorithms:
| Algorithm | Default | Minimum recommended | Option to use |
|---|---|---|---|
| Message digest | SHA-1 | SHA-256 | PKI_HASH_SHA256 |
| HMAC | HMAC-SHA-1 | HMAC-SHA-256 | PKI_HMAC_SHA256 |
| RSA signature | sha1WithRSAEncryption | sha256WithRSAEncryption | PKI_SIG_RSA_SHA256 |
| RSA encryption scheme | RSAES-PKCS1-v1_5 | RSAES-OAEP | PKI_EME_OAEP |
| Password-based encryption | pbeWithSHAAnd3-KeyTripleDES-CBC | "pkcs5PBES2" using pkcs5PBKDF2 with "aes128-CBC" | PKI_PBE_PBKDF2_AES128 |
| Symmetric encryption | des-EDE3-CBC | aes128-CBC/AES-128-GCM* | PKI_BC_AES128/PKI_AEAD_AES_128_GCM |
* Use the CIPHER_EncryptAEAD function or
Cipher.EncryptAEAD Method for AES-GCM.
We did consider changing the default options to reflect the above recommendations, but realised it would break too many existing applications. So we've just added warnings to the various parts of the manual, which we know you all read in detail.
To install on a test or developer system, use the install.exe program provided with the distribution.
This installs the core DLLs in your main Windows system directory and creates copies of all other required files,
including this manual, in the directory
C:\Program Files\CryptoSysPKI (32-bit platforms)
or C:\Program Files (x86)\CryptoSysPKI (64-bit platforms).
To distribute a Licensed Version to your end users, please read the instructions in the file distrib.txt.
You do not use the install.exe program to distribute to end users.
Note that the core DLL file is completely different for the Trial and Developer versions.
Important: You must use the install.exe
program to install the Trial version on your system
and you
must have administrator rights when installing or uninstalling.
To uninstall, use Start > Control Panel > Programs and Features > CryptoSys PKI Pro Toolkit (W10/W7/Vista) or Start > Settings > Control Panel > Add/Remove Programs > CryptoSys PKI Pro Toolkit (XP and older) to remove the application and all associated files.
The core executable file is diCrPKI.dll which is a native Windows DLL. This file must
exist in the library search path on the user's system for all programming language interfaces.
The executable diCrPKI.dll is not registered with Regsvr32 (it can't be).
The VB6/VBA and C/C++ interfaces access this core executable directly.
diCrSysPKINet.dll is a .NET Class Library which
allows programming access for C# and VB.NET projects to the "unmanaged" core executable using P/Invoke and the System.Runtime.InteropServices API.
This file is referenced from your .NET project. It is not registered.
The core native diCrPKI.dll file must exist in the library search path.
For more information on the executables, see Technical Details.
A separate version of diCrPKI.dll is provided which is compiled for X64 platforms.
Both the 32-bit and the 64-bit DLLs are installed by the setup on a 64-bit platform.
Wow64 (Windows-on-Windows 64-bit) will find and use the correct one it needs.
Please refer to our web page Using CryptoSys PKI Pro on a 64-bit system for more details.
The .NET Library DLL is compiled for both 32- and 64-bit platforms. When compiling your .NET project in MS Visual Studio, make sure you set Solution Platforms to Any CPU.
This test returns 1 if the core DLL is Win64 (X64) or 0 if Win32:
int n = General.IsWin64();
n = General.IsWin64()
long nRet; nRet = PKI_LicenceType(PKI_GEN_PLATFORM);
To get the platform as a string, either "Win32" or "X64", do this:
string s = General.Platform();
s = General.Platform()
char buf[6]; nRet = PKI_ModuleName(buf, sizeof(buf)-1, PKI_GEN_PLATFORM);
Remember, the "platform" these tests show is the platform of the core DLL that the system is using. WoW64 (Windows-on-Windows 64-bit) manages 64-bit and 32-bit applications transparently on a Windows 64-bit operating system.
When we refer to "Visual Basic" in this document we probably mean the old "classic" Visual Basic, VB6. This language, although very popular but now dropped by MS, is almost completely compatible with Visual Basic for Applications (VBA) that still comes with Microsoft Office products like MS Access and Excel.
When we refer to "VB.NET" we mean "Visual Basic .NET" or "Visual Basic 2010" or later. This is the one with the 50+ MB runtime instead of the 5 MB one for the old VB6. Everything we do here in VB.NET should be compatible in principle with every version since it was introduced in 2002 - we don't use any fancy features. However, the .NET interface is compiled for NET 4.0 and is upwardly compatible.
It would have been less confusing if MS had chosen a completely different name for the VB.NET version instead of "Visual Basic" (like, er, "Java"). The languages look similar (too similar!), but programs need to be approached in a completely different manner, at least when using our stuff.
In CryptoSys PKI Pro there is a completely different set of VB.NET (VB2010+) methods
that can be called using the VB.NET wrapper
diCrSysPKINet.dll. See the sections marked .NET Equivalent under each function
and the .NET Help File.
In general, the function FOO_DoThis in VB6 is replaced by a method Foo.DoThis in VB.NET.
The arguments and type of return value will be probably be different - there will be fewer arguments and the result is usually just returned directly
without any pre-dimensioning requirements.
Similarly, the same function FOO_DoThis in C/C++ is replaced by a method Foo.DoThis in C#
which is identical to the VB.NET method. For a quick guide, see Converting VB6 to VB.NET.
All the core VB6/C functions in this toolkit return a 32-bit signed integer value,
that is a Long in VB6/VBA and a long in C/C++, but an Integer in VB.NET
and an int in C#.
The wrapper functions provided in the .NET
interface behave differently (and more conveniently) - please
refer to the detailed documentation on that interface.
Functions either
The equivalent of the "Hello world" program for CryptoSys PKI Pro is to call the
PKI_Version function.
If this simple function call works, then it demonstrates that the Toolkit is properly installed (and vice versa!).
Here is some example source code in VB6, C, C# and VB.NET, respectively.
Public Sub ShowVersion()
Dim nRet As Long
nRet = PKI_Version(0, 0)
Debug.Print "Version=" & nRet
End Sub
#include <stdio.h>
#include "diCrPKI.h"
int main(void)
{
long version;
version = PKI_Version(NULL, NULL);
printf("Version=%ld\n", version);
return 0;
}
using CryptoSysPKI;
static void ShowVersion()
{
int ver;
ver = General.Version();
Console.WriteLine("Version={0}", ver);
}
Imports CryptoSysPKI
Shared Sub ShowVersion()
Dim ver As Integer
ver = General.Version()
Console.WriteLine("Version={0}", ver)
End Sub
Use these functions to convert a string of text to an unambiguous array of bytes and vice versa.
In VB6/VBA, use the StrConv function.
Dim abData() As Byte Dim Str As String Dim i As Long Str = "Hello world!" ' Convert string to bytes abData = StrConv(Str, vbFromUnicode) For i = 0 To UBound(abData) Debug.Print Hex(abData(i)); "='" & Chr(abData(i)) & "'" Next ' Convert bytes to string Str = StrConv(abData, vbUnicode) Debug.Print "'" & Str & "'"
48='H' 65='e' 6C='l' 6C='l' 6F='o' 20=' ' 77='w' 6F='o' 72='r' 6C='l' 64='d' 21='!' 'Hello world!'
VB6 stores its strings internally in "Unicode" format, two bytes per character, but the StrConv function will convert to an array of bytes encoded in "ANSI" format using your default code page.
In VB.NET use System.Text.Encoding.
Dim abData() As Byte Dim Str As String Dim i As Long Str = "Hello world!" ' Convert string to bytes abData = System.Text.Encoding.Default.GetBytes(Str) For i = 0 To UBound(abData) Console.WriteLine(Hex(abData(i)) & "='" & Chr(abData(i)) & "'") Next ' Convert bytes to string Str = System.Text.Encoding.Default.GetString(abData) Console.WriteLine("'" & Str & "'")
In .NET strings are stored internally in "Unicode" format (UTF-16) and the GetBytes method can extract an array of bytes in any encoding you want.
The .Default encoding uses the default code page on your system which is usually
1252 (Western European) but may be different on your setup.
If you want ISO-8859-1 (Latin-1) you can replace
.Default with .GetEncoding(28591)
(code page 28591 is ISO-8859-1 which is identical to Windows-1252 except for characters in the range 0x80 to 0x9F).
Alternatively use System.Text.Encoding.GetEncoding("iso-8859-1").GetBytes(Str).
If you want UTF-8-encoded bytes, use System.Text.Encoding.UTF8.GetBytes(Str).
In C#, use System.Text.Encoding, which has identical behaviour to the function in VB.NET.
byte[] abData;
string Str;
int i;
Str = "Hello world!";
// Convert string to bytes
abData = System.Text.Encoding.Default.GetBytes(Str);
for (i = 0; i < abData.Length; i++)
{
Console.WriteLine("{0:X}", abData[i]);
}
// Convert bytes to string
Str = System.Text.Encoding.Default.GetString(abData);
Console.WriteLine("'{0}'", Str);
In C and C++, the distinction between a string and an array of bytes is often blurred.
A string is a zero-terminated sequence of char types and
bytes are stored in the unsigned char type.
A string needs an extra character for the null terminating character;
a byte array does not, but it needs its length to be stored in a separate variable
A byte array can can contain a zero (NUL) value but a string cannot.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static void pr_hexbytes(const unsigned char *bytes, int nbytes)
/* Print bytes in hex format + newline */
{
int i;
for (i = 0; i < nbytes; i++)
printf("%02X ", bytes[i]);
printf("\n");
}
int main()
{
char szStr[] = "Hello world!";
unsigned char *lpData;
long nbytes;
char *lpszCopy;
/* Convert string to bytes */
/* (a) simply re-cast */
lpData = (unsigned char*)szStr;
nbytes = strlen(szStr);
pr_hexbytes(lpData, nbytes);
/* (b) make a copy */
lpData = malloc(nbytes);
memcpy(lpData, (unsigned char*)szStr, nbytes);
pr_hexbytes(lpData, nbytes);
/* Convert bytes to a zero-terminated string */
lpszCopy = malloc(nbytes + 1);
memcpy(lpszCopy, lpData, nbytes);
lpszCopy[nbytes] = '\0';
printf("'%s'\n", lpszCopy);
free(lpData);
free(lpszCopy);
return 0;
}
48 65 6C 6C 6F 20 77 6F 72 6C 64 21 48 65 6C 6C 6F 20 77 6F 72 6C 64 21 'Hello world!'
The types char and unsigned char
might be identical on your system, or they might not be.
We strongly recommend that you explictly distinguish between strings and byte arrays in your code by using
the correct type and consistently treating them differently.
If your string is a Unicode string, then it consists of a sequence of wchar_t types.
Converting wide-character strings to a sequence of bytes in C is more problematic.
You can either convert the Unicode string directly to a string of bytes (in which case every second byte will be zero for
US-ASCII characters),
or use the stdlib wcstombs function or the Windows WideCharToMultiByte function
to convert to a sequence of multi-byte characters (some will be one byte long, some two)
and then convert the multi-byte string to bytes (you can do this with a simple cast).
Each party encrypting and decrypting must agree on which way to do it.
To use CryptoSys PKI Pro in VB.NET, you call .NET methods instead of VB6 functions.
In almost all cases, a VB6 function like FOO_Barbaz is replaced by the .NET method Foo.Barbaz.
The .NET methods generally have fewer parameters and different return values than the equivalent VB6 function.
See the List of .NET Methods and
Cross-reference between Functions and .NET Methods.
All methods in VB.NET are "all-in-one" stateless methods and do not require the creation of an object. They are all called in a one-off manner.
Long types in VB6 must be changed to Integer in VB.NET.
All integers in CryptoSys PKI Pro are 32-bit signed integers.
You will get an exception or garbage results if you use a VB.NET Long type.
Functions that in VB6 would have output to a pre-dimensioned string or byte array will return that string or byte array directly in VB.NET. For such methods in VB.NET, an error condition is indicated by returning an empty string or byte array.
VB6/VBA
ReDim abDigest(PKI_MAX_HASH_BYTES - 1)
nRet = HASH_Bytes(abDigest(0), PKI_MAX_HASH_BYTES, abMessage(0), nMsgLen, PKI_HASH_MD5)
VB.NET
abDigest = Hash.BytesFromBytes(abMessage, HashAlgorithm.Md5)
Annotated example:
VB6/VBA
1 Debug.Print "Testing HASH_HexFromHex ..."
2 Dim strDigest As String
3 Dim nRet As Long
4 Dim strData As String
5 strDigest = String(PKI_SHA1_CHARS, " ")
6 strData = "616263"
7 nRet = HASH_HexFromHex(strDigest, Len(strDigest), strData, PKI_HASH_SHA1)
8 Debug.Print strDigest
Comments:
strDigest or else! nRet = 0 indicates success (for this function). PKI_HASH_SHA1 flag to specify hash algorithm option. Output
Testing HASH_HexFromHex ... a9993e364706816aba3e25717850c26c9cd0d89d
VB.NET
1 Console.WriteLine("Testing HASH_HexFromHex ...")
2 Dim strDigest As String
3 ''Dim nRet As Integer
4 Dim strData As String
5 ''strDigest = String(PKI_SHA1_CHARS, " ")
6 strData = "616263"
7 strDigest = Hash.HexFromHex(strData, HashAlgorithm.Sha1)
8 Console.WriteLine(strDigest)
Comments:
strDigest.Length > 0 indicates success.HashAlgorithm property to specify hash algorithm option.
To call the CryptoSys PKI Pro functions
from a classic Visual Basic VB6 project or VBA application,
just add the module basCrPKI.bas to your project
(VBA users should delete the first line Attribute VB_Name = "basCrPKI").
basCrPKI.bas.
basCrPKI64.bas, basCrPKI64_32.bas and basCrPKIWrappers.bas
must not be used and should be deleted from your projects.
The module basCrPKI.bas and distribution test code will be found in the VBA sub-directory of the installation folder, typically
C:\Program Files (x86)\CryptoSysPKI\VBA (or C:\Program Files\CryptoSysPKI\VBA on a 32-bit machine).
To find the installation folder, use Start > All Programs > CryptoSysPKI > CryptoSys PKI Reference Files.
For examples, see the test code provided in the distribution.
The "raw" core VBA/VB6 functions work in the same way as you would call the native Win32 API functions from VB6. You must use the correct variable types and must pre-dimension strings and byte arrays that are to receive output or you will suffer the wrath of the great god Gee-pee-eff.
All the functions that output to a string or byte array, or take input as byte arrays, are now available in much more convenient wrapper functions.
Using the wrapper functions means you do not have to worry about the pre-dimensioning and other hassles with passing references to bytes arrays described in the following sections. Instead, go directly to Notes on VBA wrapper functions.
To create a string of, say, length 40 characters, do either:
Dim sData As String * 40
or
Dim sData As String sData = String(40, " ")
If you know the output string needs to be the same size as the input, do this:
Dim strInput As String Dim strOutput As String strInput = "......" strOutput = String(Len(strInput), " ")
To create a byte array of a given length:
Dim abData() As Byte Dim nLen As Long nLen = 40 ReDim abData(nLen - 1)
Note that byte arrays in VBA are indexed from 0 to nLen - 1,
but an array dimensioned as abData(nLen - 1) actually has nLen elements.
To create a byte array of the same length as an existing array, do this:
Dim abOutput() As Byte ReDim abOutput(Ubound(abInput))
Traditional method: To find the length of an existing byte array:
nLen = UBound(abData) - LBound(abData) + 1
Be careful, as this will cause a run-time error if abData() has not been ReDim'd.
Safer method: Use the VBA wrapper function cnvBytesLen.
Dim ab() As Byte Debug.Print cnvBytesLen(ab) ' Expecting 0 ReDim ab(10) ' NB actually 11 elements (0..10) Debug.Print cnvBytesLen(ab) ' 11
To create a byte array with zero length do this
Dim abData() As Byte abData = vbNullString
There is no simple way to redimension a dynamic array that might have a zero length without risking a runtime error. The best you can do is as follows.
Dim abData() As Byte Dim nLen as Long ' Compute required length in bytes... nLen = ComputeLength() ' returns length, possibly zero If nLen > 0 Then ReDim Preserve abData(nLen - 1) Else abData = vbNullString End If
NULL argument in C is to use ByVal 0&.
Do not use vbNull. vbNull is not the VBA equivalent of NULL in C§.
For example, given the following definition
Public Declare Function FOO_Bar Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ...) As Long
the correct way to pass a "NULL" pointer for parameter lpOutput is as follows
nRet = FOO_Bar(ByVal 0&, 0, ...) ' Strictly correct
In this Toolkit, it is generally sufficient to set nOutBytes to be 0 and the corresponding lpOutput argument will be ignored. So the following is sufficient.
nRet = FOO_Bar(0, 0, ...) ' OK
§ We admit we have used vbNull in examples for years, believing it to be the equivalent of NULL in C.
Fortunately none of the examples caused a problem because if the length is also set to zero then it is ignored.
[Changed in v12.1] This manual has now been edited to suit.
Integer and 64-bit LongLong types are never used in CryptoSys PKI Pro.
Only 32-bit Long types are used.
Compile error: ByRef argument type mismatch
it means you have omitted the "(0)" after a Byte parameter, e.g.
Dim abData() As Byte
' ...
nRet = WIPE_Data(abData, nBytes) ' WRONG: compile error
nRet = WIPE_Data(abData(0), nBytes) ' CORRECT
Use the VBA wrapper functions to avoid the pre-dimensioning issues for functions that output to a string or byte array. See VBA Wrapper Function List.
No need to make a first pass to find the required length, or pre-dimension the output variable using String(nChars, " ") or ReDim lpOutput(nBytes-1),
and then call again (a potentially dangerous sequence of events).
The wrapper functions do it all in one line.
Dim curveName As String Dim alicePrivateKeyHex As String Dim ourPrivateKey As String Dim nChars As Long curveName = "X25519" alicePrivateKeyHex = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" ' The old long way... nChars = ECC_ReadKeyByCurve(vbNullString, 0, alicePrivateKeyHex, curveName, PKI_ECC_PRIVATE_KEY) Debug.Assert nChars > 0 ourPrivateKey = String(nChars, " ") nChars = ECC_ReadKeyByCurve(ourPrivateKey, nChars, alicePrivateKeyHex, curveName, PKI_ECC_PRIVATE_KEY) ' The new short way with a wrapper function ourPrivateKey = eccReadKeyByCurve(alicePrivateKeyHex, curveName, PKI_ECC_PRIVATE_KEY) Debug.Assert Len(ourPrivateKey) > 0
If the core VBA function name is FOO_FuncName(), then the wrapper function will be fooFuncName().
The function fooFuncName() will return the output as a string or byte array directly.
If an error occurs, the result will be a zero-length string or array.
Use the PKI_ErrorCode and pkiGetLastError() functions to get more information.
Wrapper functions that output to a byte array return the array directly. No need to ReDim. Input byte arrays are passed directly without needing the (0)
and without needing to compute the length beforehand.
' The old way - we need all the byte array lengths Dim lpKey() As Byte Dim lpIV() As Byte Dim lpPlain() As Byte Dim lpCipher() As Byte Dim nBytes As Long Dim nDataLen As Long Dim nKeyLen As Long Dim nIvLen As Long ' Set values for lpPlain, lpKey, lpIV [cut] nDataLen = cnvBytesLen(lpPlain) nKeyLen = cnvBytesLen(lpKey) nIvLen = cnvBytesLen(lpIV) nBytes = CIPHER_EncryptBytes(ByVal 0&, 0, lpPlain(0), nDataLen, lpKey(0), nKeyLen, lpIV(0), nIvLen, "Aes128/CBC/OneAndZeroes", 0) Debug.Assert nBytes > 0 ReDim lpCipher(nBytes - 1) nBytes = CIPHER_EncryptBytes(lpCipher(0), nBytes, lpPlain(0), nDataLen, lpKey(0), nKeyLen, lpIV(0), nIvLen, "Aes128/CBC/OneAndZeroes", 0)
With wrapper function:
lpCipher = cipherEncryptBytes(lpPlain, lpKey, lpIV, "Aes128/CBC/OneAndZeroes")
That's 4 extra variables we don't need, and seven lines of code is reduced to one.
Note the (0) needed in the raw function, e.g. lpPlain(0), is not required with the wrapper function.
' To pass a "null" (empty) byte array, assign `vbNullString` to the variable. Dim lpIV() As Byte lpIV = vbNullString ' Set to empty array lpCipher = cipherEncryptBytes(lpPlain, lpKey, lpIV, "Aes128/ECB")Note that you must pass a proper variable that has been Dim'd, you cannot pass
vbNullString directly for a byte array parameter.
To pass an empty String variable you can simply use either the empty string "" or vbNullString.
' To pass a "null" IV in hex, just use the empty string strCipherHex = cipherEncryptHex(strPlainHex, strKeyHex, "", "Aes128/ECB", 0)
' Or vbNullString strCipherHex = cipherEncryptHex(strPlainHex, strKeyHex, vbNullString, "Aes128/ECB", 0)
To use the "core" ANSI C interface, include the diCrPKI.h file with your source code
and link with the diCrPKI.lib library. The only non-ANSI C requirement
is that your complier supports the __stdcall
calling convention to call native API functions from a Windows native DLL.
The sample C code PKI_Examples.c provided in the distribution carries out a variety
of tests using known test vectors. There are examples given for most functions.
The "core" VB6/VBA functions and ANSI C functions are identical in form. The function names are identical, the arguments are the same (even though we may have used different parameter names in the VB and C syntaxes), and the same warnings given in the Remarks section apply to both. Just be careful to add an extra character for output string types in C.
The include file diCrPKI.h and distribution test code will be found in the C sub-directory of the installation folder, typically
C:\Program Files (x86)\CryptoSysPKI\C (or C:\Program Files\CryptoSysPKI\C on a 32-bit machine).
To find the installation folder, use Start > All Programs > CryptoSysPKI > CryptoSys PKI Reference Files.
The following type conversions apply between VB6/VBA and C/C++:-
| VB6/VBA | C/C++ |
|---|---|
| ByVal x As String | char *x |
| ByRef x As Byte | unsigned char *x |
| ByVal x As Long | long x |
You can still use Boolean type for the fEncrypt variable in VB6/VBA,
which is equivalent to a 32-bit integer when passed to the core DLL.
We recommend that you use the defined constants ENCRYPT and DECRYPT in your VB6 and C code.
Here is some minimal C code:-
/* myprog.c */ #include <stdio.h> #include "diCrPKI.h" int main(void) { long version; version = PKI_Version(NULL, NULL); printf("Version=%ld\n", version); return 0; }
To compile with MSVC++:
cl myprog.c diCrPKI.lib
Running this program should result in something similar to
Version=120300
where the actual number displayed depends on which version you have installed.
The lib file distributed with the program is made using MSVC. With Borland you need to generate a new .lib file directly from the DLL using the IMPLIB utility (note the order of the arguments):
implib dicrpki_b.lib diCrPKI.dll
To compile with Borland C++:
bcc32 mysource.c dicrpki_b.lib
The newest versions of MinGW gcc will automatically link to .LIB files created by MSVC in most cases. The .lib file we distribute works for us with MinGW 3.4.5.
To compile with MinGW:
gcc PKI_Examples.c diCrPKi.lib -o PKI_Examples
char strings require an extra char for the NUL terminating
character, so add one more to the size a VBA programmer would use
(see C/C++ users must add one to this value)
For example
char sDigest_sha1[41]; /* SHA-1 digest is 40 hex chars plus NUL */ char sDigest_sha2[65]; /* SHA-256 digest is 64 hex chars plus NUL */
or
#include <stdlib.h> char *buf; buf = malloc(PKI_MAX_HASH_CHARS + 1); // ADD ONE /* ... */ free(buf);
We recommend using the defined constants like PKI_MAX_SHA1_CHARS
and PKI_MAX_SHA1_BYTES rather than hard-coded numbers, e.g.
char sDigest_sha1[PKI_MAX_SHA1_CHARS + 1];
See the constants in diCrPKI.h.
The VBA examples in this manual use the VBA String() function to pre-dimension a string output buffer,
where nChars is number of characters to be written to the output string.
Dim strOutput As String ' VBA string type strOutput = String(nChars, " ") ' Len(strOutput) = nChars
IMPORTANT: C/C++ users must add one to this value when allocating memory.
char *szOutput; // C string type // nChars = number of characters required in output string szOutput = malloc(nChars + 1); // add one to the number of characters
Note that this is only for a C string type (char *szOutput).
For byte arrays, (unsigned char *lpOutput), use the exact number of bytes in your C/C++ code.
Dim lpOutput() As Byte ' VBA byte array type ReDim lpOutput(nBytes - 1) ' VBA array of exactly nBytes (0..nBytes-1)
unsigned char *lpOutput; // C byte array type // nBytes = number of bytes required in output byte array lpOutput = malloc(nBytes); // exact number of bytes
For examples, see the test code PKI_Examples.c and PKICheck.c
provided in the distribution (these should be in C:\Program Files (x86)\CryptoSysPKI\C)
and the examples on our web page.
The C++ (STL) interface to CryptoSys PKI is an interface to diCrPKI.dll for C++ programmers using STL (C++11 or above).
Required files to compile in a C++ project:
dipki.hpp
diCrPKI.h
dipki.cpp
#include "diCrPKI.h"
#include "dipki.hpp"
{main}.cpp
#include "dipki.hpp"
int main() { ... }
Link to diCrPKI.lib. In MSVC++, with the LIB file in the output directory (typically Debug or Release)
Configuration Properties > Linker > Input > Additional Dependencies: $(OutDir)diCrPKI.lib;%(AdditionalDependencies)
A minimal example dipki-cpp-min.cpp
#include <iostream> #include "dipki.hpp" int main() { std::cout << "Gen::Version=" << dipki::Gen::Version() << std::endl; }
Using the command-line with MSVC:
CL dipki-cpp-min.cpp dipki.cpp /EHsc /link ..\debug\diCrPKI.lib
Using GCC (make sure the DLL has been compiled for target X64):
g++ -std=c++11 dipki-cpp-min.cpp dipki.cpp "C:\fullpath\to\x64\Debug\diCrPKI.lib"
See the detailed on-line programmer's reference.
Note: All the C++ methods are static and are called directly without creating any object.
To use the .NET interface with C# and VB.NET (VB2010+):
diCrSysPKINet.dll library file into a convenient folder
(the install program puts this file by default in
C:\Program Files (x86)\CryptoSysPKI\DotNet).
diCrSysPKINet.dll.using CryptoSysPKI;or (for VB.NET)
Imports CryptoSysPKI
to your code.
Alternatively, with C#, you can just include the source code module CryptoSysPKI.cs in your project
and there is no need to reference the class library DLL.
Note that you must also have the core Win32 (or X64) executable diCrPKI.dll installed on your system
for the .NET interface to work. If not, it will throw an exception immediately:
Unhandled Exception: System.DllNotFoundException: Unable to load DLL 'diCrPKI.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
If you are working on a 64-bit system, Visual Studio will go looking for the 64-bit core DLL in the Windows system folder
(usually C:\Windows\System32).
Make sure you set the Solution Platform to be Any CPU.
The .NET class library diCrSysPKINet.dll is compiled for all platforms (Win32 and X64) and
requires at least .NET 4.0 and should be upwardly compatible with all later .NET versions.
This means that you must be using VS2010 or later.
All methods in the CryptoSysPKI .NET Class Library are static methods. You do not need to instantiate or dispose of any objects.
For examples, see the test code TestPKIcsharp.cs and TestPKIvbnet.vb
provided in the distribution.
The file diCrSysPKINet.dll and distribution test code will be found in the DotNet sub-directory of the installation folder, typically
C:\Program Files (x86)\CryptoSysPKI\DotNet (or C:\Program Files\CryptoSysPKI\DotNet on a 32-bit machine).
To find the installation folder, use Start > All Programs > CryptoSysPKI > CryptoSys PKI Reference Files.
If you need to convert old VB6 code, see Converting VB6 to VB.NET.
To combine bitwise options in .NET, use the bitwise OR operator.
With VB useOr
X509.OutputOpts.Ldap Or X509.OutputOpts.Latin1With C# use
|
X509.OutputOpts.Ldap | X509.OutputOpts.Latin1
>>> from cryptosyspki import *
>>> Gen.version() # "hello world!" for CryptoSys PKI
200600
>>> Hash.hex_from_data(b'abc') # compute SHA-1 hash in hex of 'abc' as bytes
'a9993e364706816aba3e25717850c26c9cd0d89d'
>>> Hash.hex_from_string('abc', Hash.Alg.SHA256) # same but over a string and using SHA-256
'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'
>>> h = Hash.data(b'abc') # h is a byte array (bytes->bytes)
>>> print(Cnv.tohex(h)) # display the byte array in hex
A9993E364706816ABA3E25717850C26C9CD0D89D
pip install cryptosyspki
These deprecated UTF-8-related functions are deprecated and should be replaced.
The .NET method Cnv.CheckUTF8(String) is obsolete and has been withdrawn in [v11.0].
| Deprecated | Replaced by |
|---|---|
CNV_UTF8FromLatin1 | CNV_UTF8BytesFromLatin1 |
CNV_Latin1FromUTF8 | CNV_Latin1FromUTF8Bytes |
CNV_CheckUTF8 | CNV_CheckUTF8Bytes |
Cnv.CheckUTF8(String) (withdrawn) | Cnv.CheckUTF8(Byte[]) method |
The change is subtle. Strictly speaking, the concept of "converting" a string of characters from one character encoding scheme to another is meaningless. What we really mean is that we want to change the byte array that represents the string in Latin-1 encoding to a new byte array that represents the same string using UTF-8 encoding.
The deprecated string-based functions just "forced" the UTF-8-encoded bytes back into a string type.
This forcing trick will work in VB6/C but does not in .NET (well, you can but it's a lot of effort, and pointless).
The resulting "UTF-8 strings" will print "funny" but you could pass them to HASH_HexFromString
and obtain the correct hash digest.
Aside: We had intended to completely remove these three string-based VB6/VBA functions in v11.0 but then discovered we used them ourselves in an Access VBA application to fix up UTF-8 strings from emails before saving in a database. So, er, they are reprieved.
If you need to "convert" a string to UTF-8 while using this cryptography toolkit, you probably intend to pass the result to a message digest hash or signature function. The underlying hash functions work with byte arrays anyway and so you should really just go directly from the Latin-1 string to a byte array containing bytes of the correct UTF-8 encoding. Then you can check you have the correct bytes and can pass this array directly to the "Bytes" version of the hash function.
We have also added the new function CNV_ByteEncoding and equivalent method
Cnv.ByteEncoding to convert encoding in a byte array between UTF-8 and Latin-1.
Again, by working with byte arrays, we are doing it the right way.
Both VB6 and .NET store strings internally in "Unicode" encoding (more accurately, UTF-16) but when passed to this Toolkit they are automatically converted to strings of "ANSI" characters. For more information, see Converting strings to bytes and vice versa
Here's how to change the code in VBA to obtain the SHA-1 digest of a UTF-8-encoded string using the new functions.
Dim strData As String Dim strDataUTF8 As String Dim abDataUTF8() As Byte Dim strDigest As String Dim nRet As Long Dim nLen As Long ' Our original string data strData = "Estándares de Electrónica de México para mañana" ' "Convert" to UTF-8 nLen = CNV_UTF8FromLatin1("", 0, strData) nLen = CNV_UTF8BytesFromLatin1(0, 0, strData) If nLen <= 0 Then Debug.Print "Failed to convert to UTF-8: " & nLen Exit Function End If strDataUTF8 = String(nLen, " ") ReDim abDataUTF8(nLen - 1) nLen = CNV_UTF8FromLatin1(strDataUTF8, nLen, strData) nLen = CNV_UTF8BytesFromLatin1(abDataUTF8(0), nLen, strData) ' Create a hash but first dimension the string to receive it strDigest = String(PKI_SHA1_CHARS, " ") nRet = HASH_HexFromString(strDigest, Len(strDigest), strDataUTF8, Len(strDataUTF8), PKI_HASH_SHA1) nRet = HASH_HexFromBytes(strDigest, Len(strDigest), abDataUTF8(0), nLen, PKI_HASH_SHA1) Debug.Print "Digest=" & strDigest
Digest=3eeb1871c14cd03af6d586850e3058fa80cbbe51
The same as above but using much briefer (and safer) VBA wrapper functions.
Dim strData As String Dim strDigest As String strData = "Estándares de Electrónica de México para mañana" ' Compute SHA-1 hash over UTF-8 encoded bytes in one line strDigest = hashHexFromBytes(cnvUTF8BytesFromLatin1(strData), PKI_HASH_SHA1) Debug.Print "Digest=" & strDigest
Here is code to do the same thing in VB.NET.
Dim strData As String Dim abDataUTF8() As Byte Dim strDigest As String ' Our original string data strData = "Estándares de Electrónica de México para mañana" ' "Convert" to UTF-8 abDataUTF8 = System.Text.Encoding.UTF8.GetBytes(strData) ' Compute hash value strDigest = Hash.HexFromBytes(abDataUTF8, HashAlgorithm.Sha1) Console.WriteLine("Digest=" & strDigest)
And in C#, doing it all in one line.
string strData; string strDigest; strData = "Estándares de Electrónica de México para mañana"; strDigest = Hash.HexFromBytes(System.Text.Encoding.UTF8.GetBytes(strData), HashAlgorithm.Sha1); Console.WriteLine("Digest=" + strDigest);
All functions in this Toolkit that pass a filename as an argument only support filenames in single-byte "ANSI" encoding.
So ASCII and Latin-1 filenames like abcdef.txt and México.xml are OK, but a Chinese filename like
ä½ å¥½.txt will fail.
To solve this, use a little-known hack on Windows that retrieves the short path name of a file, GetShortPathName.
This was originally designed to provide an MS-DOS-compatible form of a file path where each folder name and filename is 8 characters or fewer.
So, for example, the long name
C:\Test\Documents and Settings\My Documents\ForEmailWithALongNameLikeThisFolderHas\helloFileWithaLongNameToo.txt
reduces to something like
C:\Test\DOCUME~1\MYDOCU~1\FOREMA~1\HELLOF~1.TXT
where each component of the path name is 8 characters or fewer.
It turns out that this function will provide an ASCII-character equivalent of the name of a file in any Windows "International" UTF-16 characters. The short name is safe to use with any function in this Toolkit that requires a filename parameter.
Use the function CNV_ShortPathName to get a ASCII filename that will work with any function in this Toolkit. Examples:
| System Filename | ShortPathName |
|---|---|
| 你好.txt | FC0F~1.TXT |
| こんにちは世界.txt | C001~1.TXT |
| Приветмир.txt | E173~1.TXT |
The exact short path name may be different on your system.
The file path must exist, though. So if you want to output to a file with a name in, say, Japanese or Chinese characters, then you must create a dummy file of the required name, get its short path name, and then output to a file of that name, which will automatically overwrite the original dummy file.
diCrPKI.dll. It is intended to meet FIPS 140-2 security level 1.
The cryptographic boundary for CryptoSys PKI Pro
is defined as the enclosure of the computer on which the cryptographic module is installed.
As a pure software product, CryptoSys PKI Pro provides no physical security by itself.
The computer itself must be appropriately physically secured.
HKCU\Software\DI Management
and reads entries created by the setup utility in HKLM\Software\DI Management.
Do not attempt to change these entries.
X509_CertIsValidNow and X509_ValidatePath functions, no checks are made on
the validity period of X.509 certificates by any other functions in this toolkit, nor are the key usage flags checked.
Any correctly-formatted X.509 certificate is considered valid for any purpose.
It's up to you to make your own checks before use.
Temporary file exception: [New in v12.0] The function ASN1_TextDumpToString
and method Asn1.TextDumpToString create a locked temporary file which is automatically deleted.
The primitives in this toolkit allow you to do a lot of low-level operations with RSA and ECC keys. The original design only permitted private keys to be stored as a file in encrypted format. In response to many requests from users, we've added various functions that allow you to import and save private keys in a variety of unencrypted formats, including XML and OpenSSL-compatible PEM formats.
Use these functions in your tests by all means, but if you are using this toolkit to make an application to be used by less-experienced end users (and this is almost always the case), follow the following guidelines:
WIPE_Data function to wipe the
internal private key string as soon as you've finished using it.
WIPE_File function to erase it immediately afterwards.
Make sure this happens even if an error condition occurs.
This toolkit uses what we call an internal key string to hold a locally-encrypted copy of RSA and ECC keys. This key string is ephemeral in the sense it is only short lived. It expires at the end of your current session.
The principle is that you read in the key from a file as a one-off operation using its password into an "internal key string" and you can then use this string for other operations that require the key without requiring your important password again.
When your current session finishes (i.e. when the process ends), the internal key string is of no use. If it is accidentally printed or saved, it cannot be used to compromise your real key.
This means
RSA_KeyHashCode function.
You should always read in the key data from the private and public key files, PFX files, or X.509 certificates at the time they are required. An internal key string is a string of base64 characters but please treat it as an opaque "blob". Its structure may change without notice in a future revision.
Private keys are created and saved by default in a PKCS#8 encrypted format, protected by a password.
The default algorithm is "pbeWithSHAAnd3-KeyTripleDES-CBC" from PKCS#12.
To increase security use one of the stronger PBES2 encryption schemes from PKCS#5 v2 using the key derivation function PBKDF2:
des-EDE3-CBCaes128-CBCaes192-CBCaes256-CBC[Changed in v11.0] The above option values are a simplified alternative to PKI_PBE_PBES2+PKI_BC_AES128, etc.
The default pseudorandom function (PRF) for PBKDF2 is hmacWithSHA1.
To use a stronger HMAC function from the SHA-2 family in the PRF for PBKDF2, add one of the following options
hmacWithSHA224hmacWithSHA256hmacWithSHA384hmacWithSHA512For legacy applications, you can still use the old, less secure, PBES1 schemes using DES from PKCS#5 v1.5. These are definitely not recommended for new applications. Not available for ECC private keys.
[Changed in v11.0] note that the values for these flags have changed.
pbeWithMD5AndDES-CBC (legacy, not recommended)pbeWithMD2AndDES-CBC (legacy, not recommended)pbeWithSHA1AndDES-CBC (legacy, not recommended)Remember that the security of all these schemes is limited by the strength of the password used. Other applications may not support all the alternatives provided here.
You can use the elliptic curve cryptography functions in this toolkit to sign data using the ECDSA and EdDSA algorithms
(see SIG_SignData and SIG_SignFile and
the Sig class methods).
[New in v20.0] You can also perform elliptic curve Diffie-Hellman key exchange (ECDH) - see ECC_DHSharedSecret.
You can create your own elliptic curve keys, and read, analyze and save keys in the standard key file formats, both encrypted and unencrypted. You can read a key file into an internal key string which is stored in encrypted form valid only for the current session. We support the following curves over prime fields:
P-192, also known as secp192r1 and prime192v1P-256, also known as secp256r1 and prime256v1P-224, also known as secp224r1P-384, also known as secp384r1P-521, also known as secp521r1secp256k1 (the Bitcoin curve) Ed25519 (EdDSA only) [New in v20.0]X25519 (ECDH only) [New in v20.0]Ed448 (EdDSA only) [New in v22.0]X448 (ECDH only) [New in v22.0]brainpoolP256r1 [New in v20.4]brainpoolP384r1 [New in v20.4]brainpoolP512r1 [New in v20.4]
To create a new elliptic curve key pair, use the ECC_MakeKeys function.
This creates two new files, an encrypted private key file and a public key file.
You can use the ReadKey and SaveKey functions to read in and save these in different formats.
In this toolkit, EC public key files are always stored as DER-encoded SubjectPublicKeyInfo types [RFC5480].
In a PEM-encoded file, this should begin with -----BEGIN PUBLIC KEY.
The three supported types (all DER-encoded) for an EC private key file are:
EncryptedPrivateKeyInfo [RFC5208] encrypted with a password.
This is the (only) output when using ECC_MakeKeys and ECC_SaveEncKey.
In a PEM-encoded file, this should begin with -----BEGIN ENCRYPTED PRIVATE KEY.
ECPrivateKey [RFC5915].
This is the default output for a private key using ECC_SaveKey.
In a PEM-encoded file, this should begin with -----BEGIN EC PRIVATE KEY.
PrivateKeyInfo [RFC5208]
(more recently renamed as OneAsymmetricKey [RFC5958]
but identical in structure in this case).
This is an optional output for a private key using ECC_SaveKey with the PKI_KEY_TYPE_PKCS8 option.
In a PEM-encoded file, this should begin with -----BEGIN PRIVATE KEY.
Key files can be saved as binary (default) or PEM-encoded (with the PKI_KEY_FORMAT_PEM option). These encodings are detected automatically when reading a key file.
Use the ECC_ReadKeyByCurve function to read in a key in a
hex format string,
then you can save it as a file in a supported key format.
If your key is in base58 encoding, use CNV_Base58ToBytes to decode, then
CNV_HexStrFromBytes to obtain the hex form string
(in .NET just use Cnv.ToHex(Cnv.FromBase58(b58str))).
To change the format of an EC key file, read the file into an "internal" string using
ECC_ReadPrivateKey or
ECC_ReadPublicKey,
then save it as a file again using
ECC_SaveKey or
ECC_SaveEncKey.
To obtain the public key from a private key, read the private key into an internal string and then use
ECC_PublicKeyFromPrivate.
To analyze an EC key file, read it into an internal string and use
ECC_QueryKey.
w is represented in hex by the hexadecimal encoding of its integer value encoded in octets as per section 3 of
[RFC5915], denoted here as HEX(w).
(x,y) is represented in hex by the hexadecimal encoding of the octet string as defined in section 4.3.6 of
[X9-63]:
04||HEX(x)||HEX(y)
Compressed representation (beginning "02" or "03") is not supported due to patent issues.
Note that the format is different for the safe curves X25519, Ed25519, X448 and Ed448.
An ECDSA signature consists of a pair of integers (r,s).
There are two representations of ECDSA signatures used in this toolkit:
r and s, in that order (i.e. r||s)
as specified in section 6.4.1 of [XMLDSIG]
with a length parameter l equal to ceiling(log2(q)/8) where q is the order of the curve.
This is the default output in this toolkit.
It is the form expected for a SignatureValue in an XML-DSIG signature [RFC4050]
and is described in section E3.1 of [IEEE1363].
r and s, in that order).
This is the representation used by Bitcoin and in X.509 certificates and is an optional output in this toolkit.
Use the PKI_SIG_ASN1DER option flag.
By default, these representations are formatted in base64 encoding. Use the PKI_ENCODE_BASE64URL option to format the signature in URL-safe "base64url" encoding, or the PKI_ENCODE_HEX option for hexadecimal (base16) encoding.
Yes, as of [v12.0] we do. See, for example, X509_MakeCert and ECC_ReadPublicKey.
Definitely not! Due to patent issues, attempts to pass a public key in so-called "compressed representation" will result in a large Canadian Ogopogo monster from a swamp near Waterloo, Ontario, materialising from your computer and devouring you in a frenzy of blood and gore. Of course, you are welcome to try and see what happens.
[New in v20.0] The elliptic "safe curve" algorithms X25519 and Ed25519 are now supported in this Toolkit and [New in v22.0] so are X448 and Ed448.
X25519 and X448 are key agreement algorithms based on the Montgomery curves "curve25519" [CURVE25519] and "curve448" (also known as "goldilocks") [GOLDILOCKS]. The use of X25519 and X448 for Elliptic Curve Diffie-Hellman key exchange (ECDH) is described in [RFC7748].
Ed25519 and Ed448 are elliptic curve signature schemes Edwards-curve Digital Signature Algorithm (EdDSA) described in [RFC8032]. Ed25519 uses the twisted Edwards curve "edwards25519", which is birationally equivalent to curve25519 [ED25519].
curve25519, edwards25519 and curve448 are "safe curves" [SAFECURVES]. These have many security advantages over the standard NIST/SEC curves.
In this documentation we refer to these algorithm/curve
combinations as "safe curves" to differentiate
them from the NIST/SEC elliptic curves such as secp256r1.
There are many differences in the use of these two classes of
elliptic curves, noted below.
The terms "X25519" and "Ed25519" are used to describe the algorithm/curve combination. The convention is that "X25519" is used when curve25519 is used with the Diffie-Hellman operation, and "Ed25519" when used for the EdDSA signature operation in PureEdDSA mode [RFC8410] (similarly for "X448" and "Ed448").
The curve25519 algorithm/curve combinations are designed to operate at about the 128-bit security level equivalent to NIST P-256 or AES-128, and the curve448 combinations at around the 224-bit security level.
ECC_ReadKeyByCurve function with
safe curves, the user must explicitly specify whether the key
is a private key or public key.
SIG_SignData
function.
The core executable diCrPKI.dll is a native Windows DLL compiled using
Microsoft Visual C++ for both Win32 (x86) and X64 platforms (there are separate DLL files for each platform).
This type of file used to be called a Win32 DLL.
All programming language interfaces require this core native DLL to exist in the library search path of the user's system.
The core cryptographic functions are written in pure ANSI C with extensive internal checks for memory leaks and overflow issues.
The executable diCrPKI.dll is compatible with all versions of Windows XP and above.
It does not require any other special libraries to work apart from the standard Win32 libraries available in all
modern versions of Windows.
It is totally independent of the Microsoft Cryptographic API.
The wrapper executable diCrSysPKINet.dll is a .NET Class Library
created with Microsoft Visual C# set to target Microsoft .NET Framework 4.0 and above.
It is compiled for all target platforms: Win32 and X64.
This requires at least .NET 4.0 and should be upwardly compatible with all later .NET versions.
It can be called from programs written in C# and VB.NET (aka VB2010+).
The .NET class library calls the functions in the core native DLL using System.Runtime.InteropServices.
The source code for this wrapper DLL is provided in the distribution, which you can use directly in your C# projects instead of referencing the .NET DLL.
For more details on its use, see Using with .NET.
The module performs power-up self-tests and conditional self-tests to ensure that it is functioning properly. Power-up self-tests are performed when the module is powered up, i.e. when the DLL is first attached to the parent Windows process. Conditional self-tests are performed when certain security functions are invoked.
The following power-up self-tests are performed:-
The random number generator implementation performs the following self-tests to obtain assurance that the Deterministic Random Bit Generator (DRBG) continues to operate as designed and implemented (as per section 11.3, [SP80090A]).
The integrity of the software module is tested using a 32-bit error detection code (EDC). The value of this EDC is set and stored when the module is created. On testing, the EDC is re-computed for the DLL module file being used and compared with the stored value. If the values do not match, the test fails.
In addition to this automatic software integrity test, the integrity of the entire DLL file can be independently verified by the user using published message digest and checksum values before and after installation - see CryptoSys PKI Pro Toolkit Integrity Checks.
The following conditional tests are performed:-
When the module generates a public and private key pair, it carries out pair-wise consistency tests for both encryption and digital signing. The test involves encrypting a randomly-generated message with the public key. If the output is equal to the input message, the test fails. The encrypted message is then decrypted using the private key and if the output is not equal to the original message, the test fails. The same random message is then signed using the private key and then verified with the public key. If the verification fails, the test fails.
When the module is first loaded or instantiated in a new thread, the RNG generates a 64-bit block which is not used but is saved in thread-safe memory for comparison with the next 64-bit block to be generated. Each subsequent generation of a 64-bit block is compared with the previously generated block. The test fails if any two compared 64-bit blocks are equal. No blocks are saved that have actually been previously output by the generator.
Any failure of a power-up test or conditional test will cause the following actions to take place:
Note that you should never, ever see such a failure unless someone has interfered with the DLL file or some serious problem has occurred on your system.
* The error log file will be given a filename "pkierr.log". If the process does not have permissions to write to that directory, no log file be created.
** By terminate its own process, we mean that the CryptoSys DllMain function will return false. This will cause statically-linked applications to terminate, and applications that use LoadLibrary, like Visual Basic, to return an error message saying it cannot find the DLL file.
You can make settings in the machine's registry to prevent the message box displaying and to change the destination directory of the log file. See Optional Registry Settings. It is not possible to prevent the DLL from exiting if a critical error happens.
The user may call the power-up self-tests on demand with the PKI_PowerUpTests
function. In the event that such an "on demand" test fails, the module will log the error event and return an error
code but will not terminate the process.
Be aware that the automatic self-tests fail only in exceptional circumstances. You should never see one in practice unless the software module has been tampered with.
A Critical Error occurs if and only if one of the following events occur:
You should never see a critical error in practice unless the software module has been tampered with.
The following optional registry settings may be made to change the behaviour of the module if a critical error occurs.
Disclaimer Modifying the registry can cause serious problems that may require you to reinstall your operating system. We cannot guarantee that problems resulting from the incorrect use of the registry can be solved. Use the information provided at your own risk.
The default behaviour is to display a pop-up MessageBox if a critical error occurs. Users running the toolkit on an unattended server or within an IIS application can disable pop-ups to prevent problems (IIS gets a bit upset if an application displays a pop-up). Set the value to '1' to disable pop-up messages from appearing. Note that this will not prevent the 'first user' or expiry dialogs appearing with the Test Version.
[HKEY_LOCAL_MACHINE\Software\DI Management\CryptoSysPKI\Options]NoMessageBoxThe default behaviour if a critical error occurs is to try to write to an error log file in the same directory as the parent executable file that called the DLL. To change this directory create a REG_SZ value of 'ErrorLogDir' in the key below and set the value to the directory you want, e.g. "C:\myfolder\subdir". The directory name should not have a trailing slash character.
[HKEY_LOCAL_MACHINE\Software\DI Management\CryptoSysPKI\Options]ErrorLogDirTo disable the creation of an error log file altogether, create a REG_DWORD value of 'NoErrorLog' in the key below. Set the value to '1' to disable.
[HKEY_LOCAL_MACHINE\Software\DI Management\CryptoSysPKI\Options]NoErrorLogThe following registry entry is required for the Event Log messages to be recorded properly. If this entry is not present, or the path to the DLL is wrong, the event log entries will be of the form:
The description for Event ID ( 8xxx ) in Source ( diCrPKI ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer.
For correct formatting of the message, create the REG_SZ and REG_DWORD values in the key below. The message will still be recorded even if this entry is not present.
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\diCrPKI]EventMessageFileTypesSupportedNote that event log messages are only written in exceptional circumstances. You should never see one in practice unless the software module has been tampered with.
The random number generator used in the CryptoSys PKI Pro toolkit is designed to conform to NIST Special Publication 800-90A Recommendation for Random Number Generation Using Deterministic Random Bit Generators [SP80090A]. Entropy is accumulated in "Fortuna" pools as described in Ferguson and Schneier, Practical Cryptography, [FERG03]. The full technical details are published on our web site.
The underlying RNG functions use the algorithms recommended in NIST SP 800-90A [SP80090A] (the "DRBG Standard") to provide a Deterministic Random Bit Generator (DRBG). The HMAC_DRBG mechanism is used with SHA-512 as the underlying hash function [Updated in v22.1]. This outputs a sequence of binary bits that appears to be statistically independent and unbiased. The output is effectively random so long as internal actions of the process are hidden from observation. In particular the algorithm provides good Backtracking Resistance and, depending how it is used, good Prediction Resistance.
Entropy is accumulated at startup and whenever any function in the library is called. Only inobtrusive methods of collecting entropy are used, so you can use the Toolkit safely in any application. The "Fortuna" method of pooling is used to prevent certain attacks from someone who controls some but not all of the entropy sources (see chapter 10 of [FERG03]). The more times your application calls the functions in the library before needing some random data, the more entropy will be accumulated. The user cannot control how or when the Fortuna entropy is added to the RNG process - this is by design. The advantage of the Fortuna system is that the level of entropy does not need to be measured. There is, however, a period of vulnerability just after start up when there may not be sufficient entropy in the pools. This can be overcome by initializing with a seed file, or [New in v22.1] getting entropy seeds from the Intel(R) DRNG hardware-generated random values, if supported on your machine.
We strongly recommend that you use and initialize with a seed file wherever possible.
The Digital Random Number Generator (DRNG) is an innovative hardware approach to high-quality, high-performance entropy and random number generation. It is composed of the new Intel 64 Architecture instructions RDRAND and RDSEED and an underlying DRNG hardware implementation. For more information see [INTEL-DRNG].
If available on your system, 256 bits of entropy from Intel(R) DRNG (using hardware-generated random values) will be added automatically on first use of any RNG function. The output is used to seed and add entropy to the generator state and Fortuna accumulation pools. It is not used directly.
The availability of support can be checked using the RNG_Initialize function and passing an empty "" filename parameter.
If the return value is a positive number then Intel(R) DRNG is supported (1=RDRAND available, 2=RDSEED available, 3=both RDRAND and RDSEED available).
RDSEED will be preferred if available.
Support can also be explicitly turned off using the PKI_RNG_NO_INTEL_DRNG option.
RNG_Initialize
function to specify a seedfile with a known minimum amount of entropy
to initialise the PRNG. This seed file is updated automatically when used. You
should call the
RNG_UpdateSeedFile
from time to time in your
application to save any existing entropy, and use
RNG_MakeSeedFile
to create a new one.
The security of this
method is as good as the security you have over the seed file. If an attacker
controls the seed file, it does not mean they control the random output data; it
just means that using a seedfile does not increase the security strength of the PRNG.
RNG_BytesWithPrompt function
when generating random data to force the user to
generate entropy using random keystrokes and mouse movements.
RNG_MakeSeedFile
also uses such a prompt.
This works provided you know the user's keyboard strokes and mouse movements are secure
(e.g. are not being transmitted over a network).
RNG_Bytes function.
If you assume zero security strength for the
internally-generated entropy and you add input with, say, 128 bits of security
strength, then the output from the RNG will have at least 128 bits of security
strength.
User-supplied entropy (a.k.a. a "seed") is added as "additional input" to the generation process. It does not affect the accumulation pools and cannot be used by an attacker to control the output.
Remember it's not how "random" your user-supplied entropy is, but how little an
attacker knows about it. Using the current time is no use. If you can provide
32 bytes* of data of which an attacker knows nothing and cannot later discover,
then you have added 128 bits of security strength.
* The bytes must have been selected randomly from the range 0 to 255.
Here is an example in VB6 of how you could use the RNG to generate user-supplied entropy when creating a new pair of RSA keys. (The password should be entered separately, not hard-coded like this!)
Dim nRet As Long Dim nBits As Long Dim strPublicKeyFile As String Dim strPrivateKeyFile As String Dim strPassword As String Dim strSeed As String nBits = 512 strPublicKeyFile = "mykeypub.bin" strPrivateKeyFile = "mykeypri.bin" strPassword = "password" ' 1. Generate some user-derived entropy using the keyboard strSeed = String(64, " ") nRet = RNG_StringWithPrompt(strSeed, Len(strSeed), "", 0) ' 2. Create a new pair of RSA key files, adding this seed to the process Debug.Print "About to create a new RSA key pair..." nRet = RSA_MakeKeys(strPublicKeyFile, strPrivateKeyFile, nBits, _ PKI_RSAEXP_EQ_65537, 50, 1000, strPassword, strSeed, Len(strSeed), 0) Debug.Print "RSA_MakeKeys returns " & nRet & " (expected 0)" ' 3. Immediately wipe the sensitive data Call WIPE_String(strSeed, Len(strSeed)) Call WIPE_String(strPassword, Len(strPassword))
And the same example in C# (VB.NET is very similar)
int r;
byte[] seed;
int nbits = 512;
string publicKeyFile = @"mykeypub.bin";
string privateKeyFile = @"mykeypri.bin";
StringBuilder sbPassword = new StringBuilder("password");
// 1. Generate some user-derived entropy using the keyboard
seed = Rng.BytesWithPrompt(64,"",Rng.Strength.Default);
Debug.Assert(seed.Length > 0, "Failed to create a seed");
// 2. Create a new pair of RSA key files, adding this seed to the process
r = Rsa.MakeKeys(publicKeyFile, privateKeyFile, nbits,
Rsa.PublicExponent.Exp_EQ_65537, 1000, sbPassword.ToString(),
Rsa.PbeOptions.Default, false, seed);
Console.WriteLine("Rsa.MakeKeys returns {0} (expected 0)", r);
// 3. Immediately wipe the sensitive data
Wipe.Data(seed);
Wipe.String(sbPassword);
For more details on the security aspects of the random number generator, see the technical details published on our web site.
A distinguished name for an X.509 certificate consists of a sequence of relative distinguished names (RDN) where each RDN is expressed as an attribute type/value pair.
In this Toolkit, an RDN is specified as an attribute type/value pair in the form <type>=<value>,
for example, CN=Carol.
Multi-valued RDNs are not supported.
A distinguished name is specified as a string consisting of a sequence of attribute type/value pairs separated by a semicolon (';' U+003B).
The general format is
<type>=<value>(;<type>=<value>)*[;]
At least one attribute must be specified. The RDNs are written to the certificate name in the order they are listed. Attribute pairs may be repeated. Note that the Windows Certificate Manager displays the attributes in LDAP order, which is the reverse order to which they are written.
<type> is either a supported short name in the following table or a
dotted-decimal encoding of an ASN.1 object identifier (see Specifying an arbitrary RDN below).
| type | description | OID |
|---|---|---|
| CN | commonName | 2.5.4.3 |
| SN | surname | 2.5.4.4 |
| SERIALNUMBER | serialNumber | 2.5.4.5 |
| C | countryName | 2.5.4.6 |
| L | localityName | 2.5.4.7 |
| ST or S | stateOrProvinceName | 2.5.4.8 |
| STREET | streetAddress | 2.5.4.9 |
| O | organizationName | 2.5.4.10 |
| OU | organizationalUnit | 2.5.4.11 |
| T or TITLE | title | 2.5.4.12 |
| G or GN | givenName | 2.5.4.42 |
| E | emailAddress (deprecated) | 1.2.840.113549.1.9.1 |
| UID | userID | 0.9.2342.19200300.100.1.1 |
| DC | domainComponent | 0.9.2342.19200300.100.1.25 |
| initials | initials | 2.5.4.43 |
| generationQualifier | generation qualifier (eg "Jr.") | 2.5.4.44 |
| dnQualifier | distinguished name qualifier | 2.5.4.46 |
| pseudonym | pseudonym | 2.5.4.65 |
We keep the deprecated emailAddress attribute here because it seems so popular.
Note that the emailAddress attribute of the distinguished name
is independent of the rfc822Name address in a subjectAltName extension, which can be specified
separately in the extensions parameter.
<value> is a string of bytes (octets) to be encoded as an ASN.1 string type. A <value> can be specified in the following ways:
<astring><astring> consists only of printable ASCII characters excluding
the equals sign ('=' U+003D) and the semicolon (';' U+003B).
Some examples.
"C=US;O=Example Organisation;CN=Test User 1" "CN=Carol" "CN=My User;O=My Org;OU=Unit;C=AU;L=My Town;S=NSW;E=myuser@my.org"
All other characters are treated literally, including spaces after the '=' and before the ';'.
'<quoted-string>'<quoted-string> in single quotes (apostrophe "'" U+0027)
and use the backslash ('\' U+005C) to escape the special characters
"'" and "\". Examples:
"O='e=mc2';OU='roses are red; violets are blue'" "O='Fred\'s Bar'" => Fred's Bar "OU='This=\\E\'asy;'" => This=\E'asy
"C='M\e9xico'" => Latin-1-encoded letter é "C='M\C3\A9xico'" => UTF-8-encoded letter éIn all other cases the backslash is ignored.
"OU='p\qr'" => pqr
Note that when using C/C++, you need to double-escape the backslash character:
strDN = "CN=My User;OU='This=\\\\E\\'asy;';C='M\\C3\\A9xico'";
In C#, use a verbatim string literal:
strDN = @"CN=My User;OU='This=\\E\'asy;';C='M\C3\A9xico'";
#x<hex-digits>OU=#x616263 => abc C=#x4de97869636f => México in Latin-1 C=#x4dc3a97869636f => México in UTF-8 CN=#xE5A4A7E58DAB => CJK ideographs, U+5927 (da) and U+536B (wei) in UTF-8
The value must start with the two characters #x and be followed only by hex digits [0-9A-Fa-f].
The lower-case letter "x" is case sensitive. This form is now made redundant by using escaped hex sequences in a quoted string, but it's more compact
and, hey, it's there if you want to use it.
#<hexstring>$szDistid="$" will create an X.509 document with an empty subject name.
At least one field for a subject alternative name extension (altSubjectName) must be specified and the extension will automatically be marked critical.
(Note that's a dollar symbol "$", not an empty string, which has a different meaning.)
The default encoding is IA5String for the emailAddress (E) attribute
and PrintableString for all other attributes.
If the input string includes characters that are not valid for these encodings, then
a T61String (TeletexString) will be used instead as a fudge.
Certificates created with a T61String may not be accepted as valid by some profiles.
To force UTF-8 encoding, specify the PKI_X509_UTF8 flag.
If the PKI_X509_UTF8 flag is specified in nOptions,
all new DN attribute strings will be encoded as UTF8String.
If the UTF-8 flag is set and the value contains only valid UTF-8-encoded characters, then the string will be copied directly. Otherwise the input is assumed to be 8-bit Latin-1 and will be converted to UTF-8 accordingly, with each 8-bit character being converted to two UTF-8 bytes.
| Input string | Default encoding | With PKI_X509_UTF8 |
|---|---|---|
OU=abc | PrintableString "abc" | UTF8String "abc" |
OU=#x616263 | PrintableString "abc" | UTF8String "abc" |
OU='a\62c' | PrintableString "abc" | UTF8String "abc" |
C=M\e9xico | T61String "México" | UTF8String "México" |
C=#x4de97869636f | T61String "México" | UTF8String "México" |
C=#x4dc3a97869636f | T61String (garbage!) | UTF8String "México" |
CN=#xE5A4A7E58DAB | T61String (garbage!) | UTF8String (U+5927,U+536B) |
CN='\E5\A4\A7\E5\8D\AB' | T61String (garbage!) | UTF8String (U+5927,U+536B) |
The last two examples give the same result as two CJK ideographs, U+5927 (da) and U+536B (wei), encoded in UTF-8.
See the second example in X509_MakeCertSelf.
[New in v12.0].
To specify a relative distinguished name (RDN) with an attribute type not supported by the short names listed above,
write the type as a dotted-decimal value (e.g. 2.5.4.18, postOfficeBox)
and the value as a quoted string (e.g. 'Box 45').
Alternatively, see Full DER-encoded Value using "#" below.
"C=CA;2.5.4.18='Box 45';CN=John Doe"
The result of the example above in the final X.509 certificate should be as follows.
SEQUENCE {
SET {
SEQUENCE {
OBJECT IDENTIFIER countryName (2 5 4 6)
PrintableString 'CA'
}
}
SET {
SEQUENCE {
OBJECT IDENTIFIER postOfficeBox (2 5 4 18)
PrintableString 'Box 45'
}
}
SET {
SEQUENCE {
OBJECT IDENTIFIER commonName (2 5 4 3)
PrintableString 'John Doe'
}
}
}
For a useful list of RDN attribute types, see [RFC4519] LDAP Schema for User Applications.
Use the representation <dotted-decimal>=#<hexstring>
to specify a value that cannot be expressed as a simple string,
with <hexstring> prefixed by a pound sign ('#' U+0023) with <hexstring> being the hexadecimal encoding of the octets of the DER-encoding of the ASN.1 value.
Note there is just a single pound sign '#' preceding the hex-encoded value. The meaning is different if you use "#x".
"C=CA;2.5.4.18=#1306426F78203435;CN=John Doe"
The expresssion 2.5.4.18=#1306426F78203435 is a convoluted way to demonstrate the use of <dotted-decimal>=#<hexstring>
to represent an RDN attribute-type-and-value.
This creates an RDN of type postOfficeBox with ASN.1 value equal to the seven decoded bytes
(0x)13 06 42 6F 78 20 34 35; that is, the PrintableString (tag 0x13), of length six bytes (length byte 0x06), with data representing the string "Box 45"
as the six bytes 42 6F 78 20 34 35.
A simpler equivalent is 2.5.4.18='Box 45'.
This alternative is meant for advanced users who are comfortable with ASN.1 encodings and want to do something clever like specify the ASN.1 type for the value.
Using the '<quoted-string>' option will almost certainly do what you want in most cases.
| Syntax | Example | Remarks |
|---|---|---|
| <short-name>=<astring> | OU=abc | <astring> must not contain "=" or ";" |
| <short-name>='<quoted-string>' | OU='abc' | Surround <quoted-string> with single quotes "'"
and use backslash "\" to escape the quote and backslash \' and \\.Use a hex escape sequence \<HEX><HEX> of a backslash followed by exactly two hex digits to insert an 8-bit octet.
|
| <short-name>=#x<hex-digits> | OU=#x616263C=#x4de978 | <hex-digits> are decoded in pairs directly to octet values. |
| <dotted-decimal>=<quoted-string> | 2.5.4.11='abc' | <dotted-decimal> must decode to a valid OID; same rules for <quoted-string> as above. |
| <dotted-decimal>=#<hexstring> | 2.5.4.11=#1303616263 | <hexstring> must decode to a full DER-encoding of ASN.1 value (including tag byte and length). |
Various profiles (e.g. PKIX) set limits on the maximum length of the attribute values, e.g. the maximum length of the country code "C" is two characters. We do not enforce these limits. We also do not enforce the strict choices about the string encoding types - if you pass a character that does not fit in the "correct" encoding for the attribute, we'll kludge it into the most appropriate one. In other words, we'll put any old cr*p that you pass into the certificate distinguished name (see AOC policy).
Use the PKI_X509_LDAP option with functions X509_CertIssuerName, X509_CertSubjectName and X509_QueryCert (with queries "issuerName" and "subjectName") to obtain the LDAP string representation of the distinguished name as per [RFC4514].
The LDAP string representation lists the RDN attributeName=attributeValue pairs
separated by a comma (',' U+002C).
These are output in 'reverse order', i.e.
starting with the last element of the sequence and moving backwards toward the first.
The attribute values are converted to UTF-8 encoding with special and unprintable characters
escaped with a backslash ('\' U+005C).
Unprintable characters are output in the form "\xx" where "xx" is the hexadecimal value of the byte.
Special characters that are escaped by a backslash are any of the 7 characters ["+,;<=>],
a leading space character, a leading '#' character, a trailing space character, or the backslash character itself.
The default behaviour is to display only printable ASCII characters and escape all others. You can add the PKI_X509_UTF8 flag to output all multibyte UTF-8 characters in their encoded byte form. Alternatively you can add the PKI_X509_LATIN1 flag to convert any UTF-8 characters than can be encoded as a single byte in Latin-1 (ISO-8859-1) - this is strictly not to the LDAP specification (which requires UTF-8 encoding), but you may find it useful for display purposes: you can always save in UTF-8 encoding later.
The only RDN attributeType name strings output by the PKI_X509_LDAP option are the nine descriptions required by [RFC4514], namely
Any other attributeType will be displayed in dotted OID form, e.g. the emailAddress attribute type
normally represented by E will be output as
1.2.840.113549.1.9.1.
This LDAP string feature is intended to be used to create an <X509IssuerName> element
or <X509SubjectName> element
within a
Signature/KeyInfo/X509Data element in an XML-DSIG document.
Note that you cannot use this representation to specify a distinguished name when using X509_MakeCert. You must use the form described in Distinguished Names. The LDAP form is just for display.
The szExtensions parameter is optional and is used to set advanced options in new X.509 certificates
and certificate signing requests made using
the X509_MakeCert, X509_MakeCertSelf
and X509_CertRequest functions.
The szExtensions parameter is expected to contain a list of one or more attribute-value pairs of the form
type=value separated by a semicolon (';' U+003B) with the type names as defined below.
Valid attribute-value pairs are:
Fields for subject alternative name extension (duplicates OK):
Extensions for making X.509 certificates only (duplicates ignored):
Extensions for making X.509 certificates and certificate requests:
The type names are not case sensitive. So, for example, dnsname and DnSnaMe
and dNSName are all equivalent.
subjectAltName extension,
e.g. rfc822Name=myname@testorg.com.
subjectAltName extension,
e.g. dNSName=foo.example.net.
subjectAltName extension,
e.g. uri=http://www.ietf.org/rfc/rfc3986.txt.
subjectAltName extension,
e.g. iPAddress=192.168.15.1 or iPAddress=2001:db8:85a3:0:0:8a2e:370:7334.
IPv4 addresses must be in dotted-quad format d.d.d.d using exactly four decimal integers of value between 0 and 255.
IPv6 addresses must be in the form x:x:x:x:x:x:x:x, exactly 8 groups of one to four hexadecimal digits separated by colons.
The compressed zero form using "::" is not accepted.
Alternatively, IPv6 addresses may be specified in the base-85 notation of [RFC1924]!
serialNumber=12deadbeefcafe0123
(the decimal number 348087084311274979619).
If the first hex digit is greater than 7, it will preceded by a '00' to make sure the integer is stored as a positive value.
[New in v11.0]
Add the prefix "#d" to specify the serial number as a large decimal integer,
e.g. serialNumber=#d348087084311274979619,
or add the prefix "#x" to specify unambiguously the serial number as a hexadecimal-encoded integer,
e.g. serialNumber=#x12deadbeefcafe0123.
If no "#" prefix is found, the default is to assume hexadecimal encoding.
notAfter=2030-12-31 or notAfter=2030-12-31T14:03:59.
If no time is given it will default to 23:59:59.
Note that this time is UTC (GMT) not local.
notBefore=2008-12-31.
If no time is given it will default to 00:00:01.
Note that this time is UTC (GMT) not local.
subjectKeyIdentifier extension with an octet string (binary) value specified in hex format
e.g. subjectKeyIdentifier=fedcba9876543210.
certificatePolicies extension with a single policy information term with an object
identifier (OID) in dotted form,
e.g. certificatePolicies=2.16.840.1.101.3.2.1.48.1.
Only one policy information term can be specified and no qualifiers are permitted.
cRLDistributionPoints extension with a single DistributionPoint,
e.g. cRLDistributionPoints=http://dodgycert.example.com/evca.crl.
Only one distributionPoint can be specified and it must be a general name of type URI.
smimeCapabilities extension with one or more SMIMECapability provide a list of one or more hexadecimal strings, separated by commas ",".
Each hexstring must be a hexadecimal representation of the DER-encoded ASN.1 value of the SMIMECapability (which will always begin with "30").
The S/MIME Capabilities Extension is defined in [RFC4262].
For examples of DER encodings see section 6 of [RFC5753] and section 8 of [RFC8418].
For example, sMIMECapabilities=300B0609608648016503040102,301A060B2A864886F70D0109100313300B0609608648016503040105;
will set two smimeCapability nodes, one for aes128-CBC and the other for "ECDH with HKDF using SHA-256" (ecdhHKDF-SHA256) with aes128-wrap as the key wrapping algorithm.
SEQUENCE {
OBJECT IDENTIFIER sMIMECapabilities (1 2 840 113549 1 9 15)
OCTET STRING, encapsulates {
SEQUENCE {
SEQUENCE {
OBJECT IDENTIFIER aes128-CBC (2 16 840 1 101 3 4 1 2)
}
SEQUENCE {
OBJECT IDENTIFIER ecdhHKDF-SHA256 (1 2 840 113549 1 9 16 3 19)
SEQUENCE {
OBJECT IDENTIFIER aes128-wrap (2 16 840 1 101 3 4 1 5)
}
}
}
}
}
|
30 38 --SEQUENCE/56=0x38
06 09 --OBJECTIDENTIFIER/9=0x9
2a 86 48 86 f7 0d 01 09 0f
--sMIMECapabilities (1.2.840.113549.1.9.15)
04 2b --OCTETSTRING/43=0x2B
--encapsulates:
30 29 --SEQUENCE/41=0x29
30 0b --SEQUENCE/11=0xB
06 09 --OBJECTIDENTIFIER/9=0x9
60 86 48 01 65 03 04 01 02
--aes128-CBC (2.16.840.1.101.3.4.1.2)
30 1a --SEQUENCE/26=0x1A
06 0b --OBJECTIDENTIFIER/11=0xB
2a 86 48 86 f7 0d 01 09 10 03 13
--ecdhHKDF-SHA256 (1.2.840.113549.1.9.16.3.19)
30 0b --SEQUENCE/11=0xB
06 09 --OBJECTIDENTIFIER/9=0x9
60 86 48 01 65 03 04 01 05
--aes128-wrap (2.16.840.1.101.3.4.1.5)
|
For example,digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign, encipherOnly, decipherOnly.
"keyUsage=digitalSignature,nonRepudiation;".
Careful, for X.509 certificates, these will add to any values in nKeyUsageFlags.
By default, the keyUsage extension is marked critical (as per [PKIX]:
"When present, conforming CAs SHOULD mark this extension as critical").
[New in v20.0] To mark this extension as non-critical, include the key word noncritical in the attribute value,
e.g. "keyUsage=keyAgreement,noncritical;".
anyExtendedKeyUsage is not supported.)
To make the extension critical, appendserverAuth, clientAuth, codeSigning, emailProtection, timeStamping, OCSPSigning.
",critical".
For example, "extKeyUsage=serverAuth,clientAuth,emailProtection,critical;".
Some examples of valid input strings to the szExtensions parameter:
"rfc822name=AliceRSA@example.com" "serialNumber=46346BC7800056;subjectKeyIdentifier=77D2B4D1B74C8A8AA3CE" "rfc822Name=me@here.com;notAfter=2020-12-31T12:00:59" "rfc822Name=AliceRSA@example.com;notBefore=1999-09-19T01:08:47;notAfter=2039-12-31" "dnsname=foo.example.net;uri=ftp://ftp.is.co.za/rfc/rfc1808.txt;ipaddress=127.0.0.1" "AliceRSA@example.com" // (legacy behaviour=>rfc822Name)
Space characters are significant between the '=' and the ';',
so the following examples will produce different results.
dnsname=foo.example.com; dnsname= foo.example.com; dnsname=foo.example.com ;
If an attribute is not specified, the relevant field
will either be omitted or will default to the values set by nCertNum,
nYearsValid and the current system time.
It is an error to specify an invalid attribute name.
The attributes meant only for making X.509 certificates are not accepted for certificate signing requests,
and any duplicates of the X.509-only attributes will be ignored.
The values of ASCII strings will be copied exactly as given without any further checks, regardless of whether or not they are suitable.
For example, we don't check that the value passed for an rfc822Name is actually a valid email address.
It's up to the user to police the input to this rather sharp tool. See our AOC Policy below.
[New in v12.0] To add an arbitrary Extension to a version 3 X.509 certificate, include an attribute-value pair of the form
<dotted-decimal>=#<hexstring> in the szExtensions parameter.
Where <dotted-decimal> is a dotted decimal OID value representing the extnID of the Extension
and <hexstring> is the hexadecimal encoding of each byte of the DER-encoded ASN.1 value of the extnValue,
excluding the encapsulating OCTET STRING tag and length bytes (if you don't understand this, don't use it).
Examples
"2.16.840.1.113730.1.1=#03020410;"
2.16.840.1.113730.1.1 represents the OID for netscape-cert-type and 03020410 is the hexadecimal encoding of the
DER-encoded ASN.1 value BIT STRING with 4 unused bits: '1000'B.
"2.5.29.31=#302d302ba029a0278625687474703a2f2f646f646779636572742e6578616d706c652e636f6d2f657663612e63726c;"
2.5.29.31 represents the OID for cRLDistributionPoints and <hexstring> is the hexadecimal encoding of the
ASN.1 value:
SEQUENCE {
. SEQUENCE {
. . [0] {
. . . [0] {
. . . . [6] 'http://dodgycert.example.com/evca.crl'
. . . . }
. . . }
. . }
. }
Advanced users only. It's up to you to compose a valid DER-encoded ASN.1 value. And, yes, you can use this feature to add an MPEG video of your cat to an X.509 certificate!
",critical" to the hexstring component (no spaces, lowercase only).
For example
"2.5.29.17=#30068704c0a80f01,critical;"
This will add a critical subjectAltName extension (OID 2.5.29.17) with the value IP Address=192.168.15.1.
SEQUENCE {
. OBJECT IDENTIFIER subjectAltName (2 5 29 17)
. BOOLEAN TRUE
. OCTET STRING, encapsulates {
. . SEQUENCE {
. . . [7] C0 A8 0F 01
. . . }
. . }
. }
}
This toolkit is a set of tools to do specific cryptographic procedures that should be useful in your applications. We do not police too strongly what you do, providing the input parses OK. In particular, you can use the functions and options in here to create all sorts of wierd and wonderful X.509 certificates. Our policy is simple, we accept any old cr*p (AOC) you want to pass. It's up to you to restrict the input to whatever profile you wish to adopt.
Coming soon: addMpegVideoOfCat option :-)
[New in v12.0] Oh, yes, you can now! See Add an arbitrary X.509 Extension.
(And we used "AOC" many years before the election of any politician with the same moniker.)
Functions that require a date-time to be specified in ISO 8601 format (<iso-date-string>) will accept the following formats.
Year: YYYY (eg 2013, defaults to 2013-01-01) Year and month: YYYY-MM (eg 2013-07, defaults to 2013-07-01) Complete date: YYYY-MM-DD (eg 2013-07-16) Complete date plus hours with optional "Z": YYYY-MM-DDThh (eg 2013-07-16T19, defaults to 2013-07-16T19:00:00Z) YYYY-MM-DDThhZ (eg 2013-07-16T19Z, defaults to 2013-07-16T19:00:00Z) Complete date plus hours and minutes with optional "Z": YYYY-MM-DDThh:mm (eg 2013-07-16T19:23, defaults to 2013-07-16T19:23:00Z) YYYY-MM-DDThh:mmZ (eg 2013-07-16T19:23Z, defaults to 2013-07-16T19:23:00Z) Complete date plus hours, minutes and seconds with optional "Z": YYYY-MM-DDThh:mm:ss (eg 2013-07-16T19:23:51, defaults to 2013-07-16T19:23:51Z) YYYY-MM-DDThh:mm:ssZ (eg 2013-07-16T19:23:51Z)
where
YYYY = four-digit year
MM = two-digit month (01=January, etc.)
DD = two-digit day of month (01 through 31)
hh = two digits of hour (00 through 23) (am/pm NOT allowed)
mm = two digits of minute (00 through 59)
ss = two digits of second (00 through 59)
Z = special UTC designator ("Z") (optional)
Times are always interpreted as GMT (UTC) times regardless of whether a "Z" time zone designator is appended or not. Time zone designators of the form "+hh:mm" are not accepted. Years before 1900 are not accepted (so, sorry, no X.509 certs for Julius Caesar). Be careful, if you examine the resulting files in another time zone using other tools, like Windows Certificate Manager, the times may display differently in local time. This is not an error.
Almost all the security-related files used by this toolkit - X.509 certificates, key files, CMS data files and so forth - contain ASN.1 objects encoded in BER- or DER-encoding. You'll also come across PEM-encoded files. This section attempts to explain the differences and similarities between these terms.
For most purposes here, you can consider "BER-encoded" and "DER-encoded" to mean the same thing.
DER- and BER-encoded files are binary files.
A PEM file is an alternative way to encode the same data in a text format
(these are also referred to as "Textual Encodings", see [RFC7468]).
PEM encoding is the base64 encoding [RFC4648] of the DER-encoded data sandwiched between the encapsulating boundaries of the form
"-----BEGIN XXX-----" and "-----END XXX-----". For example,
-----BEGIN CERTIFICATE----- MIHgMIGaAgEBMA0GCSqG... -----END CERTIFICATE-----
PEM-encoded files are conventionally meant to be named .pem but can have .txt or the same
extension as their DER-encoded sibling, e.g. .cer. We don't care. Having a .txt extension
makes it easy to examine the file.
Note that we ignore the actual label in the encapsulation: we decode the inner base64 and examine the decoded bytes directly.
Other applications may not be so tolerant.
In this toolkit, where the input requires a file, we accept both DER-encoded binary files and their equivalent PEM-encoded text files automatically. We also in general accept the same data files encoded with BER-encoding. In addition, you can pass the PEM-encoded data in a string (a PEM String) instead of passing a filename. See PEM string alternative.
We do not accept the really old encrypted form of PEM files with "Proc-Type" parameters that look like
-----BEGIN EC PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,085FFED98A156DBB
hPvIVkMx6lMS3JB6so8d8JHt+...
-----END EC PRIVATE KEY-----
But we do accept the modern form with just base64 characters sandwiched between the
"-----BEGIN XXX-----" and "-----END XXX-----" boundaries, for example.
-----BEGIN ENCRYPTED PRIVATE KEY----- MIICojAcBgoqhkiG9w0BDAEDMA4ECHPQz6NdAmoFAgIH0ASCAoBKn9KXr+dm Vtc0ZhEog7t3Prs4rJazwUsXExU78ePLMquxLi/cPmqtyjb472r6XUOa... -----END ENCRYPTED PRIVATE KEY-----
RSAPublicKey specified in PKCS#1 [RFC3447]
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
Example key file formatted by DUMPASN1:
0 71: SEQUENCE {
2 64: . INTEGER
: . . 0A 66 79 1D C6 98 81 68 DE 7A B7 74 19 BB 7F B0
: . . C0 01 C6 27 10 27 00 75 14 29 42 E1 9A 8D 8C 51
: . . D0 53 B3 E3 78 2A 1D E5 DC 5A F4 EB E9 94 68 17
: . . 01 14 A1 DF E6 7C DC 9A 9A F5 5D 65 56 20 BB AB
68 3: . INTEGER 65537
: . }
The same key formatted by the ASN1_TextDump function:
30 47 --SEQUENCE/71=0x47
02 40 --INTEGER/64=0x40
0a 66 79 1d c6 98 81 68 de 7a b7 74 19 bb 7f b0
c0 01 c6 27 10 27 00 75 14 29 42 e1 9a 8d 8c 51
d0 53 b3 e3 78 2a 1d e5 dc 5a f4 eb e9 94 68 17
01 14 a1 df e6 7c dc 9a 9a f5 5d 65 56 20 bb ab
02 03 --INTEGER/3=0x3
01 00 01
--65537
--(73 bytes)
A hex dump of the raw bytes:
000000 30 47 02 40 0a 66 79 1d c6 98 81 68 de 7a b7 74 0G.@.fy....h.z.t 000010 19 bb 7f b0 c0 01 c6 27 10 27 00 75 14 29 42 e1 .......'.'.u.)B. 000020 9a 8d 8c 51 d0 53 b3 e3 78 2a 1d e5 dc 5a f4 eb ...Q.S..x*...Z.. 000030 e9 94 68 17 01 14 a1 df e6 7c dc 9a 9a f5 5d 65 ..h......|....]e 000040 56 20 bb ab 02 03 01 00 01 V .......The same key data in PEM-encoding:
-----BEGIN RSA PUBLIC KEY----- MEcCQApmeR3GmIFo3nq3dBm7f7DAAcYnECcAdRQpQuGajYxR0FOz43gqHeXcWvTr 6ZRoFwEUod/mfNyamvVdZVYgu6sCAwEAAQ== -----END RSA PUBLIC KEY-----
All ASN.1 objects used for security applications consist of an outer SEQUENCE wrapping the data inside. That means the first byte in a binary DER-encoded object will always be 0x30 (the tag value for a SEQUENCE), and the first letter in a base64/PEM encoding will be the letter capital 'M'.
Those X.509 functions which require you to pass the filename of an X.509 certificate
will accept a base64 string representation of the certificate instead.
This is the base64 string that can be obtained using the
X509_ReadStringFromFile function.
The first character in such a string should always be an "M".
You can also pass a string containing the certificate in PEM format. See PEM string alternative below for more details.
The example below shows how each of the filename, the base64 string, or the PEM-format string can be used in a typical X.509 function.
Dim nRet As Long Dim strCertFileOrB64String As String Dim strHexHash As String ' Compute the SHA-1 `thumbprint' of an X.509 certificate in two forms strHexHash = String(PKI_SHA1_CHARS, " ") ' Refer to file itself... strCertFileOrB64String = "smallca.cer" nRet = X509_CertThumb(strCertFileOrB64String, strHexHash, Len(strHexHash), 0) Debug.Print "X509_CertThumb returns " & nRet & " for '" & strCertFileOrB64String & "'" Debug.Print "SHA-1 thumbprint=" & strHexHash ' Use base64 string representation directly... strCertFileOrB64String = _ "MIHgMIGaAgEBMA0GCSqGSIb3DQEBBQUAMAwxCjAIBgNVBAMTAUEwHhcNMDcwODAyMDIwMDAxWhc" _ & "NMTEwODAyMDIwMDAxWjAMMQowCAYDVQQDEwFBMEowDQYJKoZIhvcNAQEBBQADOQAwNgIxA1KS" _ & "JlPSmQAqQgDHUISaUsCrHbIZe249i6jFtfN3rA7czrP4CXS3mjvMFf0AsxV6BwIBAzANBgkqh" _ & "kiG9w0BAQUFAAMyAACeT7GtgmBRKUN20cIyNEGneEvmNxaliuBEVkg2npbyEBgeHXOH6jqj9Ase348UN/Q=" nRet = X509_CertThumb(strCertFileOrB64String, strHexHash, Len(strHexHash), 0) Debug.Print "X509_CertThumb returns " & nRet & " for '" & strCertFileOrB64String & "'" Debug.Print "SHA-1 thumbprint=" & strHexHash ' Again using a PEM-style string... strCertFileOrB64String = _ "-----BEGIN CERTIFICATE-----" & vbCrLf _ & "MIHgMIGaAgEBMA0GCSqGSIb3DQEBBQUAMAwxCjAIBgNVBAMTAUEwHhcNMDcwODAyMDIwMDAxWhc" & vbCrLf _ & "NMTEwODAyMDIwMDAxWjAMMQowCAYDVQQDEwFBMEowDQYJKoZIhvcNAQEBBQADOQAwNgIxA1KS" & vbCrLf _ & "JlPSmQAqQgDHUISaUsCrHbIZe249i6jFtfN3rA7czrP4CXS3mjvMFf0AsxV6BwIBAzANBgkqh" & vbCrLf _ & "kiG9w0BAQUFAAMyAACeT7GtgmBRKUN20cIyNEGneEvmNxaliuBEVkg2npbyEBgeHXOH6jqj9Ase348UN/Q=" & vbCrLf _ & "-----END CERTIFICATE-----" nRet = X509_CertThumb(strCertFileOrB64String, strHexHash, Len(strHexHash), 0) Debug.Print "X509_CertThumb returns " & nRet & " for '" & strCertFileOrB64String & "'" Debug.Print "SHA-1 thumbprint=" & strHexHash
[As of v3.5, the vbCrLf CRLF characters are no longer required in the PEM-style string]
X509_CertThumb returns 40 for 'smallca.cer' SHA-1 thumbprint=a36b1bfa0af41a2785066b2d5135b67011ac3b7f X509_CertThumb returns 40 for 'MIHgMIGaAgEBMA0GCSq...(snip)...HXOH6jqj9Ase348UN/Q=' SHA-1 thumbprint=a36b1bfa0af41a2785066b2d5135b67011ac3b7f X509_CertThumb returns 40 for '-----BEGIN CERTIFICATE----- MIHgMIGaAgEBMA...(snip)...BgeHXOH6jqj9Ase348UN/Q= -----END CERTIFICATE-----' SHA-1 thumbprint=a36b1bfa0af41a2785066b2d5135b67011ac3b7f
In the same way you can pass a base64 string instead of an X.509 filename, you can pass a string containing the certificate in PEM format. The PEM format looks like
-----BEGIN CERTIFICATE----- MIHgMIGaAgEBMA0GCSqG... -----END CERTIFICATE-----
Similarly, those RSA and ECC functions which require you to pass the filename of an key file will accept a string that contains the file contents in PEM format. An key file in PEM format looks like
-----BEGIN ENCRYPTED PRIVATE KEY----- MIICojAcBgoqhkiG9w0BDAEDMA4ECHPQz6NdAmoFAgIH0ASCAoBKn9KXr+dm Vtc0ZhEog7t3Prs4rJazwUsXExU78ePLMquxLi/cPmqtyjb472r6XUOa... -----END ENCRYPTED PRIVATE KEY-----
[New in v3.5] Similarly for CMS objects.
The functions will accept all strings that start with "-----BEGIN" and are of the form
-----BEGIN FOO BAR----- (base64-encoded data) -----END FOO BAR-----
The exact word or words used for "FOO BAR" in the "BEGIN FOO BAR" and "END FOO BAR" labels do not matter (at least as far as we are concerned; other applications may object), but there must be exactly 5 hyphen (minus) characters "-" before and after the label. Any non-base64 characters found in the encoded data, including newline characters or spaces, will be ignored.
White space is ignored in the PEM string input, so there is no need to add LF or CRLF newlines at the end of each line. You can input the data as one continuous line of characters, for example.
strPem = "-----BEGIN FOO-----MIICojAcBgoqhkiG9w0BDAEDMA4E...(snip)...se348UN/Q=-----END FOO-----"
This means, for example, that you can store your certificates and encrypted private keys as strings in a database. Note that an X.509 certificate can be passed either as a plain base64 string or in PEM format; that is, both with and without the "-----BEGIN CERTIFICATE-----" encapsulation; but RSA key data can only be passed in PEM format.
This example shows how an encrypted private key can be read from a string instead of a file.
Dim strKeyPemData As String strKeyPemData = _ "-----BEGIN ENCRYPTED PRIVATE KEY-----" & _ "MIICojAcBgoqhkiG9w0BDAEDMA4ECHPQz6NdAmoFAgIH0ASCAoBKn9KXr+dm" & _ "Vtc0ZhEog7t3Prs4rJazwUsXExU78ePLMquxLi/cPmqtyjb472r6XUOa9J/v" & _ "g2gYHlJ7D7FfAdTdVbHmXWfZzdIqI+AKZmrMoIfSVSSrI8mLDXLDgJVm2Gxa" & _ "r/YJ154L4fwqWjj0b06v8nTrXTp7G3ZSxjmXc3auf8tS1RatpDuSn027jBGt" & _ "Pg2CGPjeSomOU7Efd89R+gryW3RfXaMEv1TtGmdS+szxN4TAzgFTzjzE7qJ2" & _ "+WL09hBRxSyi5JybbxblrO5zDbGJD8rq4kGawWUj4PYDpOkxQYQyK/cALEvv" & _ "EipLeWvk03CadKER3EcpL7wQT3N5wJGNx7GR3efkO7lO/VfGf6kYFsJ8Qt94" & _ "vBlgq84abgSD+rlRX03re/NLJQ00Qxl3bDrkSiRoXSfBiOeVzBVTsh03Sj4B" & _ "V0v2KLENsMXr40rMqTGfKD3V+FyYUehWEkEl3NrIVpBSJir+g4H3tl76SdNe" & _ "mq/cTtQP+EY8fpC3I46dyDXFat3wQfubw+E5nGfv7xp6vRVRRolpZx7DpuB/" & _ "z1tzO3uP0vJ0pjATriO/ZAVs6UrXx+DJ6XsfrAVt0jpW5Ngr8rm2EiD3/1T9" & _ "7q1dELJ7GzCY1dG99XVjt9ZXb7cI8zsPpT/gzQJLfeLe3U5Mdw0hKZLfPCex" & _ "0urs3ytK0XNu+jZAYeSaysG8/rHJaH74WOgJ8gnSPY4QtWsu6+3qBErS2jbq" & _ "7E2jRvBKWICVd1yiQCDq/c6s9LeYhNhZsmcWxuX9b4lG9f1LHZy0djhIYi4x" & _ "IpcEfjkTH+7zUOkMQ+fXZHtSEVFt9L2Ci49jB8YReqbfOuDFzzwsk3xxfL2h" & _ "ZoRK" & _ "-----END ENCRYPTED PRIVATE KEY-----" Dim nLen As Long Dim strPassword As String Dim strPrivateKey As String strPassword = "password" ' How long is PrivateKey string? nLen = RSA_ReadEncPrivateKey("", 0, strKeyPemData, strPassword, 0) If nLen <= 0 Then Debug.Print "ERROR: RSA_ReadEncPrivateKey returns " & nLen Exit Sub End If ' Pre-dimension the string to receive data strPrivateKey = String(nLen, " ") ' Read in the Private Key nLen = RSA_ReadEncPrivateKey(strPrivateKey, Len(strPrivateKey), strKeyPemData, strPassword, 0) If nLen <= 0 Then Debug.Print "ERROR: RSA_ReadEncPrivateKey returns " & nLen Exit Sub End If ' ... do something with the private key... Debug.Print "Private key is " & RSA_KeyBits(strPrivateKey) & " bits long." Debug.Print "KeyHashCode=" & Hex(RSA_KeyHashCode(strPrivateKey)) ' then make sure it is deleted strPrivateKey = wipeString(strPrivateKey)
This should produce the output
Private key is 1024 bits long. KeyHashCode=48BFEF2C
The same using C# with a verbatim string:
string s = @"-----BEGIN ENCRYPTED PRIVATE KEY----- MIICojAcBgoqhkiG9w0BDAEDMA4ECHPQz6NdAmoFAgIH0ASCAoBKn9KXr+dm Vtc0ZhEog7t3Prs4rJazwUsXExU78ePLMquxLi/cPmqtyjb472r6XUOa9J/v g2gYHlJ7D7FfAdTdVbHmXWfZzdIqI+AKZmrMoIfSVSSrI8mLDXLDgJVm2Gxa r/YJ154L4fwqWjj0b06v8nTrXTp7G3ZSxjmXc3auf8tS1RatpDuSn027jBGt Pg2CGPjeSomOU7Efd89R+gryW3RfXaMEv1TtGmdS+szxN4TAzgFTzjzE7qJ2 +WL09hBRxSyi5JybbxblrO5zDbGJD8rq4kGawWUj4PYDpOkxQYQyK/cALEvv EipLeWvk03CadKER3EcpL7wQT3N5wJGNx7GR3efkO7lO/VfGf6kYFsJ8Qt94 vBlgq84abgSD+rlRX03re/NLJQ00Qxl3bDrkSiRoXSfBiOeVzBVTsh03Sj4B V0v2KLENsMXr40rMqTGfKD3V+FyYUehWEkEl3NrIVpBSJir+g4H3tl76SdNe mq/cTtQP+EY8fpC3I46dyDXFat3wQfubw+E5nGfv7xp6vRVRRolpZx7DpuB/ z1tzO3uP0vJ0pjATriO/ZAVs6UrXx+DJ6XsfrAVt0jpW5Ngr8rm2EiD3/1T9 7q1dELJ7GzCY1dG99XVjt9ZXb7cI8zsPpT/gzQJLfeLe3U5Mdw0hKZLfPCex 0urs3ytK0XNu+jZAYeSaysG8/rHJaH74WOgJ8gnSPY4QtWsu6+3qBErS2jbq 7E2jRvBKWICVd1yiQCDq/c6s9LeYhNhZsmcWxuX9b4lG9f1LHZy0djhIYi4x IpcEfjkTH+7zUOkMQ+fXZHtSEVFt9L2Ci49jB8YReqbfOuDFzzwsk3xxfL2h ZoRK -----END ENCRYPTED PRIVATE KEY-----"; StringBuilder sbKeyCheck = Rsa.ReadPrivateKey(s, "password"); Console.WriteLine("Private key is " + Rsa.KeyBits(sbKeyCheck.ToString()) + " bits long"); Console.WriteLine("KeyHashCode={0,8:X}", Rsa.KeyHashCode(sbKeyCheck.ToString())); Wipe.String(sbKeyCheck);
Private key is 1024 bits long KeyHashCode=48BFEF2C
[New in v3.5] All functions that read a signed-data or enveloped-data CMS object will now accept the data in the szFileIn parameter in five forms.
PEM format is base64-encoded data encapsulated inside "-----BEGIN FOO-----" and "-----END FOO-----" boundaries.
See PEM string above. For example,
-----BEGIN PKCS7----- MIAGCSqGSIb3DQEHAqCAMIACAQExADCABgkqhkiG9w0BBwGggCSABARUaGlzBBggaXMgc29 tZSBzYW1wbGUgY29udGVudC4AAAAAAAAxDjAMAgEBMAAwADAABAH9AAAAAAAA -----END PKCS7-----
These filename-or-string forms are detected automatically and there is no longer any need
[as of v3.5] to use the PKI_CMS_FORMAT_BASE64 option flag.
One possible conflict could be if you are in the habit of naming files in the form "MAQwAgUA" without any "." extension
and pass a string that corresponds to an existing file in the current directory.
In that unlikely event, we will use the file.
However, if you use the PKI_BIG_FILE option, you must pass the filename of a BER-encoded binary file.
The generic block cipher functions CIPHER_Byte, CIPHER_Hex and CIPHER_File
allow the block cipher algorithm and mode to specified
either by a szAlgAndMode string or by using the nOptions flags, but not both.
The algorithm-and-mode parameter string combines the name of the block cipher algorithm and the mode,
e.g. "tdea/ecb".
The output from the CIPHER_Byte and CIPHER_Hex functions is always the same length as the input, and
any padding required for ECB and CBC modes must be dealt with separately
using the PAD_* functions.
The functions CIPHER_EncryptBytes and CIPHER_DecryptBytes
use the string parameter szAlgModePad
to specify the method of padding as well, e.g. "aes128/cbc/pkcs5padding".
With CIPHER_EncryptBytes the output will be longer than the input if padding is to be added.
The user must query the function first to find the correct padded length and then allocate a buffer before encrypting.
Valid algorithm names are:
| Value | Algorithm | Option |
|---|---|---|
| tdea | Triple DES, a.k.a. 3DES, des-ede3 | PKI_BC_TDEA |
| 3des | Alternative for Triple DES | PKI_BC_3DES |
| desede3 | Another alternative for Triple DES (desede is OK) | PKI_BC_DESEDE3 |
| aes128 | AES-128 | PKI_BC_AES128 |
| aes192 | AES-192 | PKI_BC_AES192 |
| aes256 | AES-256 | PKI_BC_AES256 |
We have used "TDEA" consistently in CryptoSys products to refer to the Triple DES algorithm (as in its official name "Triple Data Encryption Algorithm"). In this case, you can use any one of "tdea", "3des" or "desede3" (or "desede"). These are all equivalent and all yield identical results.
Valid mode names are:
| Value | Mode | Option |
|---|---|---|
| ecb | Electronic Code Book mode (default) | PKI_MODE_ECB |
| cbc | Cipher Block Chaining mode | PKI_MODE_CBC |
| ofb | Output Feedback mode | PKI_MODE_OFB |
| cfb | 64/128-bit† Cipher Feedback mode | PKI_MODE_CFB |
| ctr | Counter mode | PKI_MODE_CTR |
| gcm | Galois/Counter mode‡ | PKI_MODE_GCM |
† Only 64-bit CFB mode is provided for Triple DES and only 128-bit CFB mode is provided for AES.
‡ GCM is only available for AES, and only for some functions.
Some examples of valid string values for the szAlgAndMode parameter are:
| strAlgAndMode | Description | Alternative Option value |
|---|---|---|
| tdea-cbc | Triple DES in CBC mode | PKI_BC_TDEA+PKI_MODE_CBC |
| 3des-cbc | ditto | PKI_BC_3DES+PKI_MODE_CBC |
| des-ede3-cbc | ditto | PKI_BC_DESEDE3+PKI_MODE_CBC |
| tdea-ecb | Triple DES in ECB mode | PKI_BC_TDEA+PKI_MODE_ECB |
| tdea | ditto (ECB is default mode) | PKI_BC_TDEA |
| aes128-cbc | AES-128 in CBC mode | PKI_BC_AES128+PKI_MODE_CBC |
| aes256-ctr | AES-256 in Counter mode | PKI_BC_AES256+PKI_MODE_CTR |
| aes192-gcm | AES-192 in Galois/Counter mode | PKI_BC_AES192+PKI_MODE_GCM |
Punctuation and space characters and upper- and lower-case are ignored in the szAlgAndMode string, so
"tdea-cbc",
"TDeA---cBc",
"tdea cbc", and
"TDEACBC" are equivalent
(as indeed is
"t*D$e^A c@b!C!!")
It is an error to use both the szAlgAndMode and nOptions parameters to specify the algorithm and mode. The algorithm must be explicitly specified. There is no default algorithm. The default cipher mode is ECB mode, which is not recommended because of security issues. It is recommended to use either CBC or CTR mode with a IV value that is unique each time it is used with a given key.
For the functions
CIPHER_EncryptBytes,
CIPHER_DecryptBytes,
CIPHER_EncryptHex,
CIPHER_DecryptHex,
CIPHER_FileEncrypt and
CIPHER_FileDecrypt,
you can specify padding as well as the algorithm and mode.
The given padding will be added before encryption and removed after decryption according to the relevant rules.
If the padding is not given, default padding will be assumed which depends on the cipher mode.
Valid padding names are:
| Value | Padding | Option |
|---|---|---|
| nopad[ding] | No padding is added | PKI_PAD_NOPAD |
| pkcs5[padding] | The padding scheme described in PKCS#5/#7 [PKCS5] | PKI_PAD_PKCS5 |
| oneandzeroes[padding] | Pads with 0x80 followed by as many zero bytes necessary to fill the block | PKI_PAD_1ZERO |
| ansix923[padding] | The padding scheme described in ANSI X9.23 [X9-23] | PKI_PAD_AX923 |
| w3c[padding] | The padding scheme described in W3C Recommendation for XML encryption [XMLENC] | PKI_PAD_W3C |
So, for example, both nopad and nopadding are accepted, and so are pkcs5 and pkcs5padding. Remember that punctuation characters and case in the szAlgModePad string are ignored. The keywords must be in the correct order algorithm-mode-padding. Some valid examples:
| szAlgModePad | Alternative Option value |
|---|---|
| tdea/cbc/pkcs5 | PKI_BC_TDEA+PKI_MODE_CBC+PKI_PAD_PKCS5 |
| tdea/cbc/pkcs5padding | PKI_BC_TDEA+PKI_MODE_CBC+PKI_PAD_PKCS5 |
| tdeacbcpkcs5 | PKI_BC_TDEA+PKI_MODE_CBC+PKI_PAD_PKCS5 |
| aes128-ecb-oneandzeroes | PKI_BC_AES128+PKI_MODE_ECB+PKI_PAD_1ZERO |
To perform encryption with a block cipher in ECB or CBC mode the length of the input to be encrypted must be an exact multiple of the block length B in bytes. For Triple DES the block length B is 8 bytes (64 bits) and for all AES variants it is 16 bytes (128 bits). If the length of the data to be encrypted is not an exact multiple of B, it must be padded to make it so. After decrypting, the padding needs to be removed.
For other modes of encryption, such as "counter" mode (CTR) or OFB or CFB, padding is not required. In these cases the ciphertext is always the same length as the plaintext, and a padding method is not applicable.
There are many, many conventions for padding. It is up to the sender and receiver of encrypted data to agree on the convention used.
The most popular is "PKCS5" padding, described in section 6.1.1 of [PKCS5], which is the same as the padding method in section 6.3 of [CMS], section 10.3 of [PKCS7] and para 1.1 of [RFC1423].
If the block length is B then add N padding bytes of value N to make the input length
up to the next exact multiple of B.
If the input length is already an exact multiple of B then add B bytes of value B.
Thus padding of length N between one and B bytes is always added in an unambiguous manner.
After decrypting, check that the last N bytes of the decrypted data all have value N with
1 < N ≤ B.
If so, strip N bytes, otherwise throw a decryption error.
Examples of PKCS5 padding for block length B = 8:
3 bytes: FDFDFD --> FDFDFD0505050505 7 bytes: FDFDFDFDFDFDFD --> FDFDFDFDFDFDFD01 8 bytes: FDFDFDFDFDFDFDFD --> FDFDFDFDFDFDFDFD0808080808080808
For "OneAndZeroes" Padding add a byte of value 0x80 followed by as many zero bytes as is necessary to fill the input to the next exact multiple of B. Like PKCS5 padding, this method always adds padding of length between one and B bytes to the input before encryption. It is easily removed in an unambiguous manner after decryption.
The "OneAndZeroes" term comes from the fact that this method appends a 'one' bit to the input followed by as many 'zero' bits as is necessary.
The byte 0x80 is 10000000 in binary form. Note the spelling of "Zeroes", which is what everyone else seems to use.
Examples of OneAndZeroes padding for block length B = 8:
3 bytes: FDFDFD --> FDFDFD8000000000 7 bytes: FDFDFDFDFDFDFD --> FDFDFDFDFDFDFD80 8 bytes: FDFDFDFDFDFDFDFD --> FDFDFDFDFDFDFDFD8000000000000000
If N padding bytes are required (1 < N ≤ B) set the last byte as N
and all the preceding N-1 padding bytes as zero.
Examples of AnsiX923 padding for block length B = 8:
3 bytes: FDFDFD --> FDFDFD0000000005 7 bytes: FDFDFDFDFDFDFD --> FDFDFDFDFDFDFD01 8 bytes: FDFDFDFDFDFDFDFD --> FDFDFDFDFDFDFDFD0000000000000008
As described in section 5.2.1 of the W3C Recommendation for XML encryption [XMLENC].
If N padding bytes are required (1 < N ≤ B) set the last byte as N
and the preceding N-1 padding bytes as arbitrary byte values.
We include this method for completeness. It is similar to ISO10126 padding. This method is not recommended since only one padding byte is ever checked when decrypting and this opens up security vulnerabilities. Note we actually use PKCS5 padding when encrypting, which is valid because the other padding bytes are specified as "arbitrary" and using N is just as arbitrary as any other value, isn't it?
Examples of W3C padding for block length B = 8, where 'xy' is an arbitrary byte:
3 bytes: FDFDFD --> FDFDFDxyxyxyxy05 7 bytes: FDFDFDFDFDFDFD --> FDFDFDFDFDFDFD01 8 bytes: FDFDFDFDFDFDFDFD --> FDFDFDFDFDFDFDFDxyxyxyxyxyxyxy08
| Algorithm | Key size (bytes) | Block size (bytes) | IV size (bytes) | Valid ECB/CBC data lengths |
|---|---|---|---|---|
| Triple DES | 24 | 8 | 8 | 8, 16, 24, 32, ..., 8i, ... bytes |
| AES-128 | 16 | 16 | 16 | 16, 32, 48, 64, ..., 16i, ... bytes |
| AES-192 | 24 | 16 | 16 | 16, 32, 48, 64, ..., 16i, ... bytes |
| AES-256 | 32 | 16 | 16 | 16, 32, 48, 64, ..., 16i, ... bytes |
SIG_ function
The signature functions SIG_Sign* and SIG_Verify*
allow the signature algorithm to be specified either by a szAlgName string or by using a flag in nOptions.
If the szAlgName contains a non-empty string, then its value is used and overrides any signature algorithm flag in
nOptions.
If szAlgName is empty ("") then the PKI_SIG_ flag in nOptions is used.
| szAlgName | Equivalent nOptions flag |
|---|---|
| "sha1WithRSAEncryption" or "RSA-SHA1" (default) | PKI_SIG_RSA_SHA1 (0) |
| "sha224WithRSAEncryption" or "RSA-SHA224" | PKI_SIG_RSA_SHA224 |
| "sha256WithRSAEncryption" or "RSA-SHA256" | PKI_SIG_RSA_SHA256 |
| "sha384WithRSAEncryption" or "RSA-SHA384" | PKI_SIG_RSA_SHA384 |
| "sha512WithRSAEncryption" or "RSA-SHA512" | PKI_SIG_RSA_SHA512 |
| "md5WithRSAEncryption" or "RSA-MD5" | PKI_SIG_RSA_MD5 |
| "ecdsaWithSHA1" or "ECDSA-SHA1" | PKI_SIG_ECDSA_SHA1 |
| "ecdsaWithSHA224" or "ECDSA-SHA224" | PKI_SIG_ECDSA_SHA224 |
| "ecdsaWithSHA256" or "ECDSA-SHA256" | PKI_SIG_ECDSA_SHA256 |
| "ecdsaWithSHA384" or "ECDSA-SHA384" | PKI_SIG_ECDSA_SHA384 |
| "ecdsaWithSHA512" or "ECDSA-SHA512" | PKI_SIG_ECDSA_SHA512 |
| "RSA-PSS-SHA1" | PKI_SIG_RSA_PSS_SHA1 |
| "RSA-PSS-SHA224" | PKI_SIG_RSA_PSS_SHA224 |
| "RSA-PSS-SHA256" | PKI_SIG_RSA_PSS_SHA256 |
| "RSA-PSS-SHA384" | PKI_SIG_RSA_PSS_SHA384 |
| "RSA-PSS-SHA512" | PKI_SIG_RSA_PSS_SHA512 |
| "Ed25519" | PKI_SIG_ED25519 |
| "Ed448" | PKI_SIG_ED448 |
Note that the combination szAlgName="" and nOptions=0 results in the default
"sha1WithRSAEncryption".
Specialist options have been added [version 3.3] to enable users to create digital signatures suitable for use in an AUTACK message (see references [SIEM99] and [EDIFACT]). This method uses a modified version of RSA (RSA2 in P1363 parlance) together with ISO 9796-1 formatting.
To create such a digital signature, the user must carry out the following operations in sequence:
HASH_Bytes()
function.RSA_EncodeMsg().
RSA_RawPrivate().
Specific changes to enable this:
RSA_FromXMLString
function to allow the import of a restricted RSA private key from XML data consisting only of the
<Modulus>, <Exponent> and <D> fields.
The resulting "internal" key string can be used to sign raw data but cannot be saved in a private key file.
We do this so we can reproduce the examples in [EDIFACT] (and discover an error in one of their examples!)
PKI_EMSIG_ISO9796 option to the RSA_EncodeMsg and
RSA_DecodeMsg
functions to enable the user to encode and decode a message according to ISO/IEC 9796-1.
If this option is used, the message is encoded directly without the applicaton of any message digest algorithm.
It assumes that the RSA key length is exactly equal to the output length and that the most significant bit of the key modulus is set.
The user has to explicitly add the length of the key modulus in bits to the option. Yes, messy.
RSA_RawPrivate and
RSA_RawPublic
functions to sign and decrypt RSA signatures using the slightly modified method used in ISO/IEC 9796-1 and ANSI X9.31.
The user must explicitly add the option 0x6 or 0xC to nominate that the message representative f
is congruent to either 6 or 12, depending on which variant they are using.
Being congruent to 6 or 12 means that the last nibble of the message representative is either 0x6 or 0xC.
Autack requires the last nibble to be 0x6 and X9.31 requires it to be 0xC.
The method used in ISO 9796-1 has been shown to be insecure for signing plain text messages, i.e. signatures can be forged. However, it is still considered to be secure when used to encode a message digest, as done in the Autack method.
For full sample code that shows how to sign and verify a message using Autack, see our Autack page.
There are two steps:
ISO/IEC 9796-1 formatting takes a message of limited length and "weaves" it into a padded block the same size in bytes as the RSA key modulus.
It allows message recovery, but is more secure if used to format a message digest of the original message.
It requires knowledge of the exact size of the key modulus in bits.
The encoded message will always be one bit shorter than the key length, as far as significant bits are concerned.
However, the returned byte array will always be the same size as the key in bytes; i.e., ceil(keybits/8) bytes.
For an extreme case like a 1025-bit key, it will return a byte array of 129 bytes with the most significant byte zero.
We use the RSA_EncodeMsg function and pass an option parameter
consisting of the PKI_EMSIG_ISO9796
flag plus the actual size of the key in bits. Do not use any other flags.
To decode and recover the message, use the RSA_DecodeMsg function
in the same manner. In VB6/VBA:
' Encapsulate hash digest in ISO9796-1 encoding ' -- we need a block of the same length as the key in bytes nKeyBits = RSA_KeyBits(strPrivateKey) Debug.Print "RSA key length=" & nKeyBits & " bits" blen = RSA_KeyBytes(strPrivateKey) ReDim abBlock(blen - 1) ' plus pass the exact key length in bits as part of the option parameter... r = RSA_EncodeMsg(abBlock(0), blen, abDigest(0), dlen, PKI_EMSIG_ISO9796 + nKeyBits) Debug.Print "RSA_EncodeMsg returns " & r & " (expecting >=0)" If (r < 0) Then Exit Function Debug.Print "Encoded block ready to sign=" & vbCrLf & cnvHexStrFromBytes(abBlock)
In C# and VB.NET/VB20xx, use the special Rsa.EncodeMsgIso9796 and Rsa.DecodeMsgIso9796 methods.
keyStr = Rsa.FromXMLString(xmlKey, false);
keyBits = Rsa.KeyBits(keyStr);
Console.WriteLine("Private key is {0} bits long", keyBits);
// Compute message digest of data
hexDigest = Hash.HexFromString(msgStr, HashAlgorithm.Sha1);
Console.WriteLine("Message-to-encode=Digest={0}", hexDigest);
// Convert digest to byte array
msg = Cnv.FromHex(hexDigest);
// Encode digest using ISO-9796-1
b = Rsa.EncodeMsgIso9796(msg, keyBits);
Debug.Assert(b.Length > 0, "Failed to Encode for ISO9796-1");
The RSA2 method of signing is described in ANSI X9.31 and IEEE P1363. It is also known as the Rabin method. We only offer the variant for an odd exponent. The method saves one bit in output compared to the PKCS#1v.15 method - even a whole byte if the key is say, 1025 bits. Yes!
For an input message representative, f, with private key (n,d) and f < n,
the output signature, s, is the minimum of
fd mod n and n - (fd mod n).
The last nibble of the message representative must be either 0x6 or 0xC (12) depending on the scheme,
i.e. f ≡ 6 (mod 16) or f ≡ 12 (mod 16).
' Sign block with RSA private key to create signature ' -- use special ISO9796/X9.31/P1363 RSA2 method with magic value 0x6 r = RSA_RawPrivate(abBlock(0), blen, strPrivateKey, &H6) Debug.Print "RSA_RawPrivate returns " & r & " (expecting 0)" If (r <> 0) Then Exit Function ' Convert to hex encoding strHexSig = cnvHexStrFromBytes(abBlock)
In C# and VB.NET/VB20xx, use the Rsa.RawPrivate and Rsa.RawPublic
methods respectively to sign and verify the encoded block. Use the overload with
the specialist option to pass the value of the "magic nibble".
// Sign block with RSA private key
// -- use special RSA2 method with magic nibble value 6
b = Rsa.RawPrivate(b, keyStr, 0x6);
// Convert to hex encoding
s = Cnv.ToHex(b);
Cryptographic Message Syntax (CMS) is a syntax used to digitally sign, digest, authenticate, or encrypt
arbitrary message content. CMS is a stricter subset of PKCS#7.
There are several CMS content types but S/MIME currently only uses four of them, namely
Data, SignedData, EnvelopedData, and CompressedData content types.
This Toolkit provides the means to create digitally-signed SignedData,
encrypted EnvelopedData and CompressedData objects* according to
the CMS specification [CMS] and some of its more recent updates.
* Pedantic note: Strictly speaking, the objects produced are
CMS SignedData or EnvelopedData objects
wrapped in a CMS ContentInfo object.
A SignedData object is a digitally-signed container for arbitrary message content. You can create
a SignedData object using one of the
CMS_MakeSigData,
CMS_MakeSigDataFromString,
CMS_MakeSigDataFromSigValue, or
CMS_MakeDetachedSig
functions.
eContent) may be included or not (the latter case
is known as a "detached signature").To verify that the message content was indeed signed by the signer requires the recipient to do the following:
The function
CMS_VerifySigData
carries out steps 2 and 3 directly with options for the user to pass the signer's certificate details if they are not already included
and also to pass the message digest of the eContent for detached signatures.
The function
CMS_GetSigDataDigest
will extract the message digest, if possible, to enable the user to perform their own separate comparison
with an independently-computed message digest of the eContent. Note that being able to retrieve the message digest
with this function implicitly verifies that the purported signer really did use their private key to sign the object.
However,
unlike the CMS_VerifySigData function, success with this function does not necessarily mean that the signer actually signed
the eContent itself. Furthermore, if the signer used the DSA or RSA-PSS signature algorithms and did not include message attributes,
then you cannot directly extract the message digest of the eContent.
To extract just the certificates themselves from a SignedData object, use the
X509_GetCertFromP7Chain
function. This will work for all types of SignedData objects, not just the "certs-only" type.
Include the option PKI_CMS_ADD_SIGNINGCERT (Cms.SigDataOptions.AddSigningCertificate)
to add an ESS Signing Certificate Attribute to the signed attributes.
The signing certificate attribute is designed to prevent simple substitution and re-issue attacks
by cryptographically linking the certificate used to create the signature with the signature itself.
This is required for B-level conformance with CAdES-BES [CADES], which in turn refers to
ESS [RFC2634] and [RFC5035].
Include the option PKI_CMS_ADD_ALGPROTECT (Cms.SigDataOptions. AddAlgProtection)
to add an Algorithm Protection Attribute to the signed attributes.
This is in accordance with [RFC6211].
If a CMS validator supports this attribute (which this Toolkit now does - see CMS_VerifySigData),
then additional checks are made to protect against signature and message digest algorithm substitution attacks.
An EnvelopedData object contains encrypted content for one or more recipients. You can create
an EnvelopedData object using one of the
CMS_MakeEnvData,
CMS_MakeEnvDataFromString, or
CMS_MakeEnvDataFromBytes
functions.
The content is encrypted with a single, randomly-generated content encryption key (CEK). Each recipient is provided with this CEK encrypted specifically for them using one of four key management techniques. The combination of the encrypted content and one encrypted CEK is called a digital envelope for that recipient. An EnvelopedData object consists of a set of RecipientInfo types, one for each recipient, and the encrypted content.
There are four key management techniques.
KeyTransRecipientInfo (ktri) typeKeyAgreeRecipientInfo (kari) typeKEKRecipientInfo (kekri) typePasswordRecipientinfo (pwri) typeAs of [v20.6], all four key management techniques are supported. ktri has always been supported. Support for kari was added in [v20.5], and support for kekri and pwri added in [v20.6].
key transport (ktri). The CEK is encrypted in the recipient's public key.
We support the RSAES-PKCS1-v1_5 and the RSAES-OAEP encryption schemes.
Options: RSAES-OAEP can specify the hash algorithm to be used and the hash algorithm to be used with the MGF.
key agreement (kari). The recipient's public key and the sender's private key are used to generate a pairwise symmetric key, which is used to encrypt the CEK.
All elliptic curve public keys we support can be used in this mode. A key derivation function (KDF) and a key wrap algorithm must be specified.
Options: Supported KDFs are the ANSI-X9.63-KDF key derivation function and the HMAC-based Key Derivation Function (HKDF) from RFC 5869.
Additonal user key material (UKM) may be provided. Triple DES key wrap and the AES key wrap algorithms are supported.
symmetric key-encryption keys (kekri). The CEK is encrypted in a previously distributed symmetric key-encryption key.
Options: Triple DES key wrap and the AES key wrap algorithms are supported. Restricted to one recipient per document.
passwords (pwri). The CEK is encrypted in a key-encryption key derived from a password as described in [RFC3211].
The PWRI-KEK key wrap algorithm specified in section 2.3 of RFC3211 is used together with the PBKDF2 key derivation algorithm.
Options: The hash algorithm and iteration count used with PBKDF2 can be specified. Restricted to one recipient per document.
| Parameter | ktri | kari | kekri | pwri |
|---|---|---|---|---|
| certList | †cert[s] | †cert[s] | †"@kekri" | †"@pwri" |
| cipherAlg | ✓ | ✓ | ✓ | ✓ |
| keyEncrAlg | ✓ | N/A | N/A | N/A |
| hashAlg | ✓ | ✓ | N/A | ✓ |
| advOpts | ✓ | ✓ | ✓ | ✓ |
| kdfAlg | N/A | ✓ | N/A | N/A |
| keyWrapAlg | N/A | ✓ | ✓ | N/A |
| keyString | N/A | ukm | †kekstr | †password |
| count | N/A | N/A | N/A | iterCount |
[New in v20.6] If an authenticated encryption algorithm is used to encrypt the content, then an AuthEnvelopedData object is created as per [RFC5083]. This is similar to an EnvelopedData object but contains an additional authentication tag field (a.k.a. MessageAuthenticationCode, mac). We provide support for AuthEnvelopedData using the AES-GCM and [New in v22.0] ChaCha20Poly1305 algorithms and all the key management techniques decribed above.
The standard tag length for AES-GCM is 16 bytes, and a truncated tag of 12, 13, 14, or 15 bytes is permitted. For some reason the default length in RFC5083 is given as 12 bytes but we always provide a 16-byte tag.
This toolkit produces enveloped-data and signed-data CMS objects which can be used in S/MIME v3 messages. To send the output as an email message you first need to wrap it in a MIME body, and to decrypt or verify an incoming message you need to extract the CMS object first.
Use the SMIME_Wrap function or
Smime.Wrap method
to create an S/MIME file from binary CMS signed-data, enveloped-data and compressed-data objects,
and the SMIME_Extract function or
Smime.Extract method
to extract the body from an S/MIME file.
The output from the CMS_MakeEnvData
or CMS_MakeEnvDataFromString function
is a CMS object. This CMS object needs to be inserted into an application/pkcs7-mime MIME entity
before being sent as an email message.
The CMS object is sent as an attachment to the email, usually with the name smime.p7m.
If your email program allows you to tailor the headers, you should identify the Content-Type as
application/pkcs7-mime; smime-type=enveloped-data.
Most email programs convert the binary CMS object file into base64 encoding automatically.
If not, you can use the PKI_CMS_FORMAT_BASE64 option to generate the output directly
in base64 encoding.
Ann creates a message for Ben using the default option:
nRet = CMS_MakeEnvDataFromString("smime.p7m", _
"Be in bar at 7 pm wearing a red rose", "ben.cer", "", 0, 0);
The output file smime.p7m will be in binary BER-encoded format.
To send as an S/MIME email, you attach this file to your email message and you need to add the following headers:-
Date: Mon, 23 Feb 2004 12:00:52 +1100
From: alice@example.com
To: ben@example.com
Subject: Secret message
MIME-Version: 1.0
Content-Type: application/pkcs7-mime;
smime-type=enveloped-data; id="smime.p7m"
Content-Transfer-Encoding: base64
Content-Description: attachment;filename=smime.p7m
MIAGCSqGSIb3DQEHA6CAMIACAQAxgZMwgZACAQAwOjA0MQswCQYDVQQGEwJBVTEV
...
When Bob receives the email, he can either:-
CMS_ReadEnvData function.
Identifying the Content-Type as application/pkcs7-mime and enveloped-data
should ensure that the receiving email
program correctly identifies the file as an encrypted email and treats it accordingly. This is optional,
and you may find it more convenient to agree with your sending parties not to do this so you can just save the attached data file directly
without getting involved in the "security" hoops that programs like Outlook Express will put you through.
If you can't save the attachment file directly from your email program, remember that email files are just
simple text files (even though they may have a .EML extension) and can be edited using a simple text editor
like NotePad. Open the email in your favorite text editor and do a cut-and-paste of the attachment data to another file.
There are two formats for signed messages for S/MIME:
The first format is simpler for our purposes. It consists of a signed-data CMS object which includes the
signed content as created by the default
CMS_MakeSigData or CMS_MakeSigDataFromString
functions.
The MIME headers are similar to the enveloped-data example above:-
MIME-Version: 1.0
To: ben@example.com
From: ann@example.com
Subject: Signed message
Date: Mon, 23 Feb 2004 12:00:52 +1100
Content-Type: application/pkcs7-mime; smime-type=signed-data;
name=smime.p7m
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=smime.p7m
MIIDmwYJKoZIhvcNAQcCoIIDjDCCA4gCAQExCTAHBgUrDgMCGjAtBgkqhkiG9w0BBwGgIA
QeDQpUaGlzIGlzIHNvbWUgc2FtcGxlIGNvbnRlbnQuoIIC4jCCAt4wggKdoAMCAQICAgDI
...
To read, just save the attachment to your hard drive and read the file with
CMS_ReadSigData or CMS_ReadSigDataToString.
The second format, S/MIME multipart/signed, includes the actual content in the body of the email message
and attaches a "detached signature" signed-data object identified as
Content-Type: application/pkcs7-signature; name=smime.p7s
in the MIME part header. This has the advantage that the signed content can be read directly in the email message,
but you need a more sophisticated email program to create the final message.
The detached signature CMS object can be created using the
CMS_MakeDetachedSig function.
A typical multipart/signed message is:
MIME-Version: 1.0 To: ben@example.com From: ann@example.com Subject: Multi-part signed message Date: Mon, 23 Feb 2004 12:00:52 +1100 Content-Type: multipart/signed; micalg=SHA1; boundary="----=_NextBoundry"; protocol="application/pkcs7-signature" This is a multi-part message in MIME format. ------=_NextBoundry This is some sample content. ------=_NextBoundry Content-Type: application/pkcs7-signature; name=smime.p7s Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename=smime.p7s MIIDeQYJKoZIhvcNAQcCoIIDajCCA2YCAQExCTAHBgUrDgMCGjALBgkqhkiG9w0BBwGggg LiMIIC3jCCAp2gAwIBAgICAMgwCQYHKoZIzjgEAzASMRAwDgYDVQQDEwdDYXJsRFNTMB4X ... ------=_NextBoundry--
You are strongly recommended to use quoted-printable encoding for the content part of the message to prevent the signed data being changed during transmission.
For more details on how to insert your CMS objects into MIME bodies (honest, that's the term they use), please refer to S/MIME Version 3 Message Specification [SMIME-MSG] and Examples of S/MIME Messages [SMIME-EX]. Stallings also covers the topic well in Cryptography and Network Security [STAL].
You can create most of the cryptographic elements required in the
[XML-DSIG] and [XML-ENC] specifications to insert into XML documents.
These XML values should be encoded in base64 encoding.
Use
CNV_B64StrFromBytes or
Cnv.ToBase64
to convert byte arrays into base64 encoding.
Here is a selection of some elements you can create.
SignatureValue element
Use
Sig.SignData
or
Sig.SignFile.
Alternatively, use
Rsa.EncodeMsgForSignature followed by
Rsa.RawPrivate
then
Cnv.ToBase64.
DigestValue elementUse
Hash.BytesFromBytes
or
Hash.BytesFromFile
then
Cnv.ToBase64.
X509Certificate elementX509IssuerSerial elementUse
X509.QueryCert with query "serialNumber" and
X509.OutputOpts.Decimal.
X509SubjectName elementUse
X509.QueryCert with query "subjectName" and
X509.OutputOpts.Ldap.
RSAKeyValue element
Use
Rsa.KeyValue or
Rsa.ToXMLString.
RSAKeyPair element
Use
Rsa.ToXMLString.
CipherValue element
xmlenc#rsa-1_5:
Use
Rsa.EncodeMsgForEncryption
with Rsa.EME.PKCSv1_5 option
followed by
Rsa.RawPublic
then
Cnv.ToBase64
xmlenc#rsa-oaep-mgf1p:
As for xmlenc#rsa-1_5 except use
Rsa.EME.OAEP option.
xmlenc#tripledes-cbc: Use
Cipher.Encrypt
with options
CipherAlgorithm.Tdea,
Mode.CBC and
padding.Pkcs5,
then
Cnv.ToBase64.
xmlenc#aes128-cbc:
As for xmlenc#tripledes-cbc except use
CipherAlgorithm.Aes128 option.
xmlenc#aes192-cbc:
As for xmlenc#tripledes-cbc except use
CipherAlgorithm.Aes192 option.
xmlenc#aes256-cbc:
As for xmlenc#tripledes-cbc except use
CipherAlgorithm.Aes256 option.
Use the optional PKI_ENCODE_BASE64URL option when creating a signature with
SIG_SignData or Sig.SignData
to output the signature value in base64url encoding suitable for inserting in a JSON Web Signature.
Base64url encoding is defined in [RFC7515] to use the URL- and filename-safe character set in section 5 of [RFC4648] with all trailing "=" characters omitted.
The base64url character set is identical to base64 except "+" (plus sign, U+002B) is replaced by "-" (hyphen-minus, U+002D), and "/" (slash, U+002F) by "_" (underscore, U+005F).
For example, the byte array represented in hexadecimal by "FEDCBAF8765432" is represented by "/ty6+HZUMg==" in base64 and "_ty6-HZUMg" in base64url.
The original intention of this Toolkit was to provide a set of primitives to carry out S/MIME operations using relatively high-level functions. However, we get so many questions about using the "raw" RSA functions that we've added this section on techniques.
The functions RSA_RawPublic and RSA_RawPrivate just carry out the basic RSA encryption or decryption operation on a "raw" block of data. The block must be exactly the same length in bytes as the length of the RSA key modulus; it must obey certain mathematical properties (in practice, make sure the first byte is zero); and it should be "padded" in a certain way to improve security and make it easier to pass to other systems (the built-in cryptographic functions in .NET hide this part of the process from you).
Encryption and signing use the same RSA operations:
In practice, there are rules to pad the input data before applying the RSA transformation.
Use the function RSA_EncodeMsg to encode or "pad" the message data you want to
encrypt or sign. This uses the rules in [PKCS#1].
Then use the appropriate RSA_Raw function with the public or private RSA key.
To encrypt some data:
use
Rsa.EncodeMsgForEncryption
with either the Rsa.EME.PKCSv1_5 option
or the Rsa.EME.OAEP option,
followed by
Rsa.RawPublic.
The length of the data you can encrypt is limited by the size of the RSA key modulus. This is typically used to encrypt a session key.
The data is padded with random bytes before encryption, so the result is always different.
To sign some data: use
Rsa.EncodeMsgForSignature followed by
Rsa.RawPrivate.
The length of the data to be signed is effectively unlimited (well, with some very large limit) because EncodeMsg creates a message digest of the
data. If your data-to-be-signed is short enough, it is possible to avoid the EncodeMsg step
and construct a block to be signed containing the original data (Hint: make sure the first byte is zero).
Use the functions RSA_Encrypt and RSA_Decrypt to carry out RSA encryption and decryption more conveniently and securely in one step.
In .NET use the Rsa.Encrypt and Rsa.Decrypt methods.
To sign data in one step, use SIG_SignData
(Sig.SignData Method).
To verify a signature, use SIG_VerifyData
(Sig.VerifyData Method).
There are two RSA signature schemes specified in [PKCS1]: RSASSA-PKCS1-v1_5 and RSASSA-PSS (RSASSA = RSA Signature Scheme with Appendix). RSASSA-PSS is a probabilistic signature scheme (PSS) with appendix. A signature scheme with appendix requires the message itself to verify the signature (i.e. the message is not recoverable from the signature).
There are also two RSA encryption schemes: RSAES-PKCS-v1_5 and RSAES-OAEP (Optimal Asymmetric Encryption Padding). Both use random seeds (and so produce a different ciphertext value each time), but RSA-OAEP is more robust and is the recommended alternative.
The PKCS-V1_5 schemes are "self contained": the signature values and ciphertext values contain all the information needed to verify or decipher.
In contrast, both the RSA-PSS and RSA-OAEP schemes require parameters which need to be provided separately.
Both require a hash function to be specified and both use a mask generation function (MGF).
There is currently only one MGF specified, called MGF1.
This in turn uses a hash function (the "MGF hash function") which may be different from the scheme hash function.
More details below.
Incidentally, the terms "function" and "algorithm" are used interchangeably here. The term "algorithm" was used in the early PKCS#1 specifications (and is reflected in the ASN.1 type names), and "function" is used in the more recent ones.
The signature schemes RSASSA-PKCS-v1_5 ("PKCSV1_5") and RSASSA-PSS ("PSS") have differences.
The default parameters for RSASSA-PSS are:
hashAlgorithm sha1, maskGenAlgorithm mgf1SHA1 (the function MGF1 with SHA-1) saltLength 20, trailerField trailerFieldBC (the byte 0xbc)
It is recommended that the MGF hash function be the same as the scheme hash algorithm/function, and that the salt length be hLen, the length of the output of the hash function.
"".
This is the only option available in this Toolkit.
The default parameters for RSASSA-OAEP are:
hashAlgorithm sha1, maskGenAlgorithm mgf1SHA1 (the function MGF1 with SHA-1) pSourceAlgorithm pSpecifiedEmpty (label L is an empty string)
It is recommended that the MGF hash function be the same as the scheme hash algorithm/function.
The mask generation function (MGF) is always MGF1 from section B.2.1 of PKCS1 (currently there is no other MGF function defined).
Note that the scheme hash function and the MGF hash function can be different.
In this Toolkit, the default hash function is SHA-1.
You can specify a different hash function using the nOptions argument.
If you do so then the MGF1 hash algorithm will also be same hash function (this is recommended practice).
Add the PKI_MGF_MGF1SHA1 option to force the MGF hash function to be SHA-1 (which, strictly speaking, is still the default).
You cannot set any other combinations of scheme and MGF1 hash functions in this Toolkit.
The default salt length for RSA-PSS is hLen, the length of the output of the hash function in bytes.
You can change the salt length when creating a signature using the PKI_PSS_SALTLEN_* options.
In this Toolkit, the "trailer byte" for RSA-PSS is always 0xbc and the label L for RSA-OAEP is always the empty string; these cannot be changed.
Note also that there are physical limitations in the length of message digest used in the MGF function with RSA-PSS and RSA-OAEP: you cannot, for instance, use the SHA-512 MGF digest function with a 1024-bit RSA key (the digest is too long).
[New in v23.0] The RSA Key Encapsulation Mechanism (RSA-KEM) Algorithm is a one-pass (store-and-forward) cryptographic mechanism for an originator to securely send keying material to a recipient using the recipient's RSA public key. ("KEM" stands for "key encapsulation mechanism".)
Using the RSA-KEM Algorithm with the Cryptographic Message Syntax (CMS) is described in [RFC5990bis]. It makes use of the KEMRecipientInfo structure as specified in [RFC9629] as part of a CMS OtherRecipientInfo ("ori") type.
RSA-KEM provides higher security assurance than traditional uses of the RSA algorithm (e.g. RSAES-PKCS1-v1_5) because the input to the underlying RSA operation is a random integer without any structure that can be exploited, and the input is independent of the keying data so the result of the RSA decryption operation is not directly available to an adversary.
This Toolkit supports RSA-KEM using KEMRecipientInfo with key derivation functions KDF2, KDF3 and HKDF; key-wrap algorithms aes*-wrap (where * is 128, 192 or 256) and hash functions SHA-* (where * is 256, 384 or 512). To use, call CMS_MakeEnvData with the option flag PKI_CMS_RSA_KEM. The default options are KDF3 with aes128-wrap and SHA-256. Triple-DES and SHA-1 are not supported for this implementation of RSA-KEM.
[New in v20.0]
Support is provided for Elliptic Curve Diffie-Hellman (ECDH) operations using the ECC_DHSharedSecret and
.NET Ecc.DHSharedSecret Method.
These functions enable you to compute the shared secret given your own private EC key and the other party's public EC key. Note this shared secret (often denoted ZZ or Z) is usually not used directly itself, but is passed to another function such as a key derivation function, perhaps with other agreed parameters. These subsequent operations are out of scope here.
Note also that there are two ways to compute the shared secret using the NIST/SEC curves. One way using the cofactor and one without. The former is referred to as "ECC Cofactor Diffie-Hellman (ECC CDH)" in [SP800-56A] and "ECSVDP-DHC" in [IEEE1363], and the latter as "ECSVDP-DH" in [IEEE1363] and [RFC5349]. BUT all the NIST/SEC curves in this toolkit have a cofactor of one, so you get the same result with either calculation.
There is only one accepted way to compute the shared secret using the safe curves X25519 and X448 - see [RFC7748].
The algorithms AES with Galois/Counter Mode (AES-GCM) and ChaCha20Poly1305 provide both authenticated encryption (confidentiality and authentication) and the ability to check the integrity and authentication of additional authenticated data (AAD) that is sent in the clear. AES-GCM is specified in NIST Special Publication 800-38D [SP800-38D] and ChaCha20Poly1305 in [RFC8439].
There are four inputs for authenticated encryption: the secret key, initialization vector (IV) (sometimes called a nonce†), the plaintext itself, and optional additional authentication data (AAD). The nonce and AAD are passed in the clear. There are two outputs: the ciphertext, which is exactly the same length as the plaintext, and an authentication tag (the "tag"). The tag is sometimes called the message authentication code (MAC) or integrity check value (ICV).
This Toolkit provides authenticated encryption using AES-GCM according to "RFC 5116 An Interface and Algorithms for Authenticated Encryption" [RFC 5116], and [New in v22.0] using ChaCha20Poly1305 as in [RFC8439]. We also add support for the AES-192-GCM algorithm (RFC 5116 only has AES-128-GCM and AES-256-GCM).
We add the further restriction that AES-GCM must have a fixed-length nonce (IV) of exactly 12 bytes (96 bits) and it can only create a fixed-length tag of exactly 16 bytes (128 bits). There is no option to use different lengths for the IV or tag. The tag is automatically appended to the output of the encryption operation. The IV may optionally be prepended to the output in accordance with section 5.2.4 of "XML Encryption Syntax and Processing Version 1.1" [XMLENC].
† Note that the term "IV" is used here to mean exactly the same as "nonce".
[New in v22.0] This toolkit has all the basic cryptographic primitives required to carry out the hybrid public key encryption (HPKE) scheme described in [RFC9180]; namely Elliptic Curve Diffie-Hellman (ECDH) key agreement (see ECC_DHSharedSecret), HMAC-based key derivation function (HKDF) using SHA2 (see KDF_Bytes), and authenticated encryption with additional data (AEAD) (see CIPHER_EncryptAEAD).
Specific functions
HPKE_LabeledExtract and HPKE_LabeledExpand
are provided here to carry out LabeledExtract() and LabeledExpand().
The function HPKE_DerivePrivateKey is provided to derive an EC private key using the deterministic method
described in HKPE. The corresponding public key can be derived using ECC_PublicKeyFromPrivate.
Note that these functions are intended to be used in an object-oriented language like C# or Python, not in raw ANSI C or VB6.
See the code hpke_test.py on our web site for an example.
In this implementation, the KDF algorithm is chosen automatically to match the KEM ECDH group curve as follows (from Table 2 in [RFC9180]).
| KEM | ECDH group | KDF |
|---|---|---|
DHKEM(P-256, HKDF-SHA256 |
P-256 | HKDF-SHA256 |
DHKEM(P-384, HKDF-SHA384 |
P-384 | HKDF-SHA384 |
DHKEM(P-521, HKDF-SHA512 |
P-521 | HKDF-SHA512 |
DHKEM(X25519, HKDF-SHA256 |
X25519 | HKDF-SHA256 |
DHKEM(X448, HKDF-SHA512 |
X448 | HKDF-SHA512 |
Furthermore, the ciphersuite's KDF is assumed to be always equal to the DHKEM's associated KDF from the above table.
Because these are all standalone functions with no context, the ECDH curve group used in the scheme must be specified. This automatically defines the KDF and associated HMAC algorithm to be used as per the above table.
The LabeledExtract() and LabeledExpand() functions facilitate domain separation of KDF calls by incorporating a label
and a suite_id which has a value derived from identifiers for the EC curve group, the KDF algorithm and, sometimes, the AEAD algorithm.
Note that the suite_id value is different depending on where the KDF is used.
In this implementation, specifying the curve name will automatically select the corresponding KDF algorithm, and the absence or presence of an option flag for
an AEAD algorithm dictates whether the KDF is being used inside a KEM algorithm (zero flag) or in the remainder of HPKE (specific AEAD algorithm flag).
The string literal "HPKE-v1" is currently hardcoded into the LabeledExtract() and LabeledExpand() functions.
Future implementations may offer an alternative if the specification is changed.
A brief but not exhaustive description of these terms.
A (cryptographic) hash function takes an arbitrary length input (message) and outputs a fixed length message digest or digest value. An eXtendable Output Function (XOF) is similar to a hash function but the output can be extended to any desired length. The security requirements of a XOF are the same as a cryptographic hash function in that it should be resistant to preimage and collision attacks. There are no secret inputs.
An example of a hash function is SHA-256 [FIPS180], available with HASH_Bytes. SHAKE128 and SHAKE256 are XOFs with security strengths of 128 bits and 256 bits respectively based on the SHA3 hash algorithm [FIPS202], available with XOF_Bytes.
The Mask Generation Function MGF1 described in [PKCS1] and used in the RSA-OEAP and RSA-PSS schemes can also be used as an XOF. For example, MGF1-SHA-256 is used as a XOF in the SPHINCS+ hash-based quantum-resistant signature scheme [SPHINCS] (see section 7.2.2, Hmsg); it is available with XOF_Bytes.
A Message Authentication Code (MAC) is a cryptographic checksum on data that uses a symmetric key to detect both accidental and intentional modifications of the data.
HMAC (Hash-based Message Authentication Code) is based on a hash function and takes a message and a key and outputs a security code, also called a tag. The security requirement for a MAC is that it must resist attempts by an adversary to forge tags. An example of an HMAC function is HMAC-SHA-256, available with HMAC_Bytes. The output from an HMAC function is a fixed length corresponding to its underlying hash function. The output can be truncated at the cost of lower security.
KMAC (KECCAK Message Authentication Code) is a variable-length keyed hash function described in NIST SP800-185 [SP800-185]. It is based on KECCAK, the core SHA-3 algorithm. There are two variants, KMAC128 and KMAC256, which have expected security strengths of 128 and 256 bits, respectively. If not specified, the convention is that the output lengths for KMAC128 and KMAC256 are 256 bits (32 bytes) and 512 bits (64 bytes), respectively. The KMAC algorithm can theoretically output an infinitely-long stream of bytes, so it can also be used as a Pseudorandom function (PRF). Note that you cannot truncate a KMAC output value when used as a message authentication code. KMAC is available with PRF_Bytes
A PseudoRandom Function (PRF) takes in a secret key and a message, and outputs a bit string. The security requirement for a PRF is that it should behave like a random function when evaluated on arbitrary messages provided the secret key is uniformly distributed. This is a stronger requirement than for a MAC. You can use a PRF to construct a MAC (like KMAC) but the converse is not necessarily true. A secure MAC function is not necessarily a secure PRF.
A Key Derivation Function (KDF) takes in some secret keying material and outputs a uniformly distributed bit string. The keying material does not have to be uniformly distributed and an adversary may have prior knowledge about part of it. Thus a KDF has a stronger security requirement than a PRF. A PRF requires a uniformly-distributed secret key, but a KDF can cope with weaker material. By definition, a KDF is a PRF, but the converse is not true.
An example of a KDF is HKDF, the HMAC-based Key Derivation Function from [RFC5869], available with KDF_Bytes.
Thus we have a hierarchy KDF > PRF > MAC.
These are the "raw" functions called directly by VB6/C programs. For the .NET method equivalents, see the List of .NET Methods and Cross-reference between Functions and .NET Methods.
Index: ASN.1 | Block Cipher | CMS | Conversion | Compression | CRL | ECC | General | Hash | HMAC | HPKE | KDF | OCSP | Padding | PBE | PEM files | PFX | PRF | Prompt | RNG | RSA Keys | RSA (Raw) | SIG | S/MIME | Triple DES (TDEA) | Wipe | X.509 Certificates | XOF
ASN1_TextDump - Dumps details of ASN.1 formatted data to a text file.ASN1_TextDumpToString - Dumps details of ASN.1 formatted data to a string.ASN1_Type - Describes the type of ASN.1 data.CIPHER_EncryptBytes - Encrypts an array of bytes using specified block cipher algorithm, mode and padding.
CIPHER_DecryptBytes - Decrypts an array of bytes using specified block cipher algorithm, mode and padding.
Supersedes:
CIPHER_Bytes - Encrypts/decrypts an array of bytes using specified block cipher algorithm and mode - @deprecated.CIPHER_FileEncrypt - Encrypts a file using specified block cipher algorithm, mode and padding.CIPHER_FileDecrypt - Decrypts a file using specified block cipher algorithm, mode and padding.
Supersedes:
CIPHER_File - Encrypts/decrypts a file using specified block cipher algorithm and mode - @deprecated.CIPHER_EncryptHex - Encrypt hex-encoded data using specified block cipher algorithm, mode and padding.CIPHER_DecryptHex - Decrypt hex-encoded data using specified block cipher algorithm, mode and padding.
Supersedes:
CIPHER_Hex - Encrypts/decrypts data in a hex-encoded string using specified block cipher algorithm and mode - @deprecated.CIPHER_EncryptAEAD - Encrypt data using an authenticated encryption algorithm.CIPHER_DecryptAEAD - Decrypt data using an authenticated encryption algorithm.CIPHER_KeyWrap - Wraps a content-encryption key with a key-encryption key.CIPHER_KeyUnwrap - Unwraps a content-encryption key with a key-encryption key.CMS_MakeEnvData - Create a CMS enveloped-data object.CMS_MakeEnvDataFromString - ditto using data directly from a string instead of a file.CMS_MakeEnvDataFromBytes - ditto using data directly from a byte array.CMS_ReadEnvData - Reads and decrypts a CMS enveloped-data object.CMS_ReadEnvDataToString - ditto writing data directly into a string instead of a file.CMS_ReadEnvDataToBytes - ditto writing data directly into a byte array.CMS_MakeSigData - Create a CMS signed-data object using sender's private key.CMS_MakeSigDataFromString - ditto using data directly from a string instead of a file.CMS_MakeSigDataFromBytes - ditto using data directly from a byte array.CMS_MakeSigDataFromSigValue - ditto using a pre-computed signature value.CMS_MakeDetachedSig - Create a "detached signature" CMS signed-data object from message digest of content.CMS_ReadSigData - Reads content from a CMS signed-data object file.CMS_ReadSigDataToString - ditto writing content data into a string instead of a file.CMS_ReadSigDataToBytes - ditto writing content data into a byte array.CMS_GetSigDataDigest - Extracts message digest from a CMS signed-data object file and verifies the signature.CMS_VerifySigData - Verifies signature and content of a CMS signed-data object file.CMS_QuerySigData - Queries a CMS signed-data object file for selected information.CMS_QueryEnvData - Queries a CMS enveloped-data object file for selected information.CMS_MakeComprData - Create a CMS compressed-data file (.p7z) from an existing input file.CMS_ReadComprData - Read and extract the decompressed contents of a CMS compressed-data file.CNV_B64StrFromBytes - Encodes byte data into a base64-encoded string.CNV_BytesFromB64Str - Decodes a base64-encoded string into bytes.CNV_B64Filter - Removes non-base64 characters from a string.CNV_HexStrFromBytes - Encodes byte data into hexadecimal string.CNV_BytesFromHexStr - Decodes a hexadecimal-encoded string into bytes.CNV_HexFilter - Removes non-hexadecimal characters from a string.CNV_Base58FromBytes - Encodes an array of bytes into a base58-encoded string.CNV_Base58ToBytes - Decodes a base58-encoded string into an array of bytes.CNV_ReverseBytes - Reverses the order of a byte array.CNV_NumFromBytes - Converts the leftmost four bytes of an array to a 32-bit integer.CNV_NumToBytes - Converts a 32-bit integer to an array of 4 bytes.CNV_Latin1FromUTF8Bytes - Converts UTF-8 encoded array of bytes into a Latin-1 string, if possible.CNV_UTF8BytesFromLatin1 - Converts a Latin-1 string into UTF-8 encoded array of bytes.CNV_ByteEncoding - Converts encoding of byte array between UTF-8 and Latin-1.CNV_CheckUTF8Bytes - Checks if a byte array contains valid UTF-8.CNV_CheckUTF8File - Checks if a file contains valid UTF-8.CNV_Utf8FromWide - Maps a UTF-16 (wide character) string to a UTF-8-encoded string.CNV_ShortPathName - Retrieve the Windows short path form of the specified path.CNV_CheckUTF8 - Checks if a string is valid UTF-8 - @deprecated.CNV_Latin1FromUTF8 - Converts a UTF-8 string into a Latin-1 string, if possible - @deprecated.CNV_UTF8FromLatin1 - Converts a Latin-1 string into a UTF-8 string - @deprecated.COMPR_Compress - Compress data using zlib compression.COMPR_Uncompress - Uncompress data using zlib compression.X509_MakeCRL - Creates an X.509 Certificate Revocation List (CRL).X509_CheckCertInCRL - checks whether an X.509 certificate has been revoked in a Certificate Revocation List (CRL).ECC_MakeKeys - Generate an EC public/private key pair and save as two key files.ECC_ReadKeyByCurve - Read an EC key from its hexadecimal (base16) representation.ECC_ReadPrivateKey - Read an EC private key from a file into an internal key string.ECC_ReadPublicKey - Read an EC public key from a file into an internal key string.ECC_SaveEncKey - Save an internal EC private key string to an encrypted private key file.ECC_SaveKey - Save an internal EC key string to a key file.ECC_PublicKeyFromPrivate - Convert an internal EC private key string into an internal public key string.ECC_QueryKey - Query an EC key string for selected information.ECC_KeyHashCode - Compute the hash code of an "internal" ECC public or private key string.ECC_DHSharedSecret - Compute EC Diffie-Hellman (ECDH) shared secret.PKI_LastError - Get the last error message set by the toolkit.PKI_ErrorCode - Return the last error code.PKI_ErrorLookup - Get a description of an error code.PKI_Version - Get the release version as an integer value.PKI_CompileTime - Get date and time the DLL was last compiled.PKI_ModuleName - Get the name of process module.PKI_ModuleInfo - Get additional information about the core DLL module.PKI_PowerUpTests - Carry out power-up tests.PKI_LicenceType - Return the licence type.PKI_Platform - Gets the platform of the core DLL.HASH_Bytes - Creates a cryptographic hash digest in byte format from byte data.HASH_File - Creates a cryptographic hash digest in byte format from a file.HASH_HexFromBytes - Creates a cryptographic hash digest in hex format from byte data.HASH_HexFromFile - Creates a cryptographic hash digest in hex format from a file.HASH_HexFromHex - Creates a cryptographic hash digest in hex format from hex-encoded data.HASH_Length - Return length of the message digest in bytes.HMAC_Bytes - Creates a keyed-hash HMAC in byte format from byte data.HMAC_HexFromBytes - Creates a keyed-hash HMAC in hex format from byte data.HMAC_HexFromHex - Creates a keyed-hash HMAC in hex format from hex-encoded data.HPKE_DerivePrivateKey - Derive an EC private key in a deterministic manner from input keying material using the DeriveKeyPair algorithm in RFC9180. HPKE_LabeledExpand - Compute the output of the LabeledExpand function as defined in RFC9180.HPKE_LabeledExtract - Compute the output of the LabeledExtract function as defined in RFC9180.KDF_Bytes - Generate a key-encryption key (KEK) from input keying material using a key derivation function (KDF).KDF_ForCms - Generate a key-encryption key (KEK) for ECDH key exchange in a CMS EnvelopedData object.OCSP_MakeRequest - Creates an Online Certification Status Protocol (OCSP) request as a base64 string.OCSP_ReadResponse - Reads a response to an Online Certification Status Protocol (OCSP) request and outputs the main results in text form.PAD_BytesBlock - Creates an input block suitably padded for encryption by a block cipher in ECB or CBC mode.PAD_UnpadBytes - Removes the padding from an encryption block.PAD_HexBlock - Creates a hex-encoded input block suitably padded for encryption by a block cipher in ECB or CBC mode. PAD_UnpadHex - Removes the padding from a hex-encoded encryption block. PBE_Kdf2 - Derives a key of any length from a password using the PBKDF2 algorithm from PKCS #5.PBE_Kdf2Hex - Derives a key of any length from a password using the PBKDF2 algorithm from PKCS #5 with the salt and output derived key encoded in hexadecimal.PBE_Scrypt - Derives a key of any length from a password using the SCRYPT algorithm.PBE_ScryptHex - Derives a key of any length from a password using the SCRYPT algorithm with the salt and derived key encoded in hexadecimal.PEM_FileFromBinFile - Converts a binary file into a PEM file.PEM_FileFromBinFileEx - Converts a binary file into a PEM file with extended options.PEM_FileToBinFile - Converts the contents of a PEM file into a binary file.PFX_MakeFile - Creates a simple PFX (PKCS-12) file from X.509 certificate and (optional) encrypted private key file.PFX_VerifySig - Verifies a PFX (PKCS-12) file signature.PWD_Prompt - Prompts for a password.PWD_PromptEx - Prompts for a password with extra options.RNG_Bytes - Generates a random set of byte data.RNG_BytesWithPrompt - ditto with a prompt to enter random keystrokes.RNG_String - Generates a string of random chars (classic VB6/VBA only) - @deprecated.RNG_StringWithPrompt - Generates a string of random chars with a prompt (classic VB6/VBA only) - @deprecated.RNG_Number - Generates a random number in a given range.RNG_Guid - Generate a random 36-character Global Unique IDentifier (GUID) string.RNG_Initialize - Initializes the RNG from a seed file.RNG_MakeSeedFile - Creates a new seed file, prompting for entropy.RNG_UpdateSeedFile - Updates an existing seed file.RNG_Test - Carries out a health check and a FIPS-140-2 statistical test on the RNG.RNG_TestDRBGVS - Test the RNG for conformance to NIST SP800-90A using the relevant test specified in DRBGVS.RSA_MakeKeysXtd - Generate an RSA key pair and save as two key files.
Supersedes:
RSA_MakeKeys - Generate an RSA key pair - @deprecated.RSA_ReadAnyPrivateKey - Reads from a file or string containing a private key into an "internal" private key string.
Supersedes:
RSA_ReadEncPrivateKey - Reads private key string from a PKCS-8 EncryptedPrivateKeyInfo file - @deprecated.RSA_ReadPrivateKeyInfo - Reads private key string from an (unencrypted) PrivateKeyInfo file - @deprecated.RSA_ReadPrivateKeyFromPFX - Reads private key string from a PKCS-12 PKCSShroudedKeybag - @deprecated.RSA_ReadAnyPublicKey - Reads from a file or string containing a public key into an "internal" public key string.
Supersedes:
RSA_ReadPublicKey - Reads public key string from a PKCS-1 RSAPublicKey file - @deprecated.RSA_GetPublicKeyFromCert - Reads public key string from an X.509 certificate - @deprecated.RSA_SaveEncKey - Save an internal RSA private key string to an encrypted private key file.
Supersedes:
RSA_SaveEncPrivateKey - Saves a private key string to a PKCS-8 EncryptedPrivateKeyInfo file - @deprecated.RSA_SavePrivateKeyInfo - Saves a private key string to an (unencrypted) PKCS-8 PrivateKeyInfo file.RSA_SavePublicKey - Saves a public key in a PKCS-1 RSAPublicKey file.RSA_PublicKeyFromPrivate - Converts an internal RSA private key string into an internal public key string.RSA_GetPrivateKeyFromPFX - Extracts a private key file from a PKCS-12 PKCSShroudedKeybag.RSA_ToXMLString - Creates an XML string representation of an RSA internal key string.RSA_ToXMLStringEx - Creates an XML string representation of an RSA internal key string with option to add a namespace prefix.RSA_FromXMLString - Creates an RSA key string in internal format from an XML string.RSA_CheckKey - Checks if an RSA key string is valid.RSA_KeyBits - Returns length of key in bits given public or private key string.RSA_KeyBytes - Returns length of key in bytes given public or private key string.RSA_KeyHashCode - Returns a hash code of a public or private key string.RSA_KeyMatch - Verifies that a pair of private and public key strings are matched.RSA_KeyValue - Extracts a base64-encoded RSA key value from internal key string.RSA_RawPublic - Transforms raw data using an RSA public key.RSA_RawPrivate - Transforms raw data using an RSA private key.RSA_EncodeMsg - Creates an EME or EMSA encoded message block according to PKCS#1.RSA_DecodeMsg - Decodes an EME or EMSA encoded message block according to PKCS#1.RSA_Encrypt - Encrypt a short message using RSA encryption.RSA_Decrypt - Decrypt a message encrypted using RSA encryption.SIG_SignData - Compute a signature value over data in a byte array.SIG_SignFile - Compute a signature value over data in a file.SIG_VerifyData - Verify a signature value over data in a byte array.SIG_VerifyFile - Verify a signature value over data in a file.SMIME_Wrap - Wrap a CMS object in an S/MIME entity.SMIME_Extract - Extract the body from an S/MIME entity.SMIME_Query - Query an S/MIME entity.TDEA_BytesMode - Encrypts/decrypts an array of bytes using Triple DES.TDEA_HexMode - Encrypts/decrypts a hex-encoded string using Triple DES with hex-encoded key and IV.TDEA_B64Mode - Encrypts/decrypts a base64-encoded string using Triple DES with base64-encoded key and IV.TDEA_File - Encrypts/decrypts a file using Triple DES and PKCS#5/#7 padding.X509_MakeCert - Creates an X.509 certificate.X509_MakeCertSelf - Creates a self-signed X.509 certificate.X509_CertRequest - Creates a PKCS-10 certification signing request (CSR).X509_VerifyCert - Verifies that an X.509 certificate has been signed by its issuer.X509_CertThumb - Calculates the message digest thumbprint of an X.509 certificate.X509_CertIsValidNow - Verifies that an X.509 certificate is currently valid.X509_CertIssuedOn - Returns string containing date and time certificate was issued on.X509_CertExpiresOn - Returns string containing date and time certificate expires.X509_CertSerialNumber - Extracts serial number of X.509 certificate.X509_CertIssuerName - Extracts issuer's distinguished name from X.509 certificate.X509_CertSubjectName - Extracts subject's distinguished name from X.509 certificate.X509_HashIssuerAndSN - Calculates the message digest hash of the issuer-and-serial-number value of an X.509 certificate.X509_GetCertFromP7Chain - Extracts an X.509 certificate file from a PKCS-7 "certs-only" certificate chain file.X509_GetCertFromPFX - Extracts an X.509 certificate file from a PKCS-12 PFX/.p12 file.X509_ReadCertStringFromP7Chain - Reads an X.509 certificate into a base64 string from PKCS-7 "certs-only" data.X509_ReadCertStringFromPFX - Reads an X.509 certificate into a base64 string from PKCS-12 PFX/.p12 data.X509_KeyUsageFlags - Returns a bitfield containing the keyUsage flags.X509_QueryCert - Queries a X.509 certificate file for selected information.X509_ReadStringFromFile - Creates a base64 string of the X.509 certificate file.X509_SaveFileFromString - Creates a new X.509 certificate file from a base64 string.X509_TextDump - Dumps details of X.509 certificate (or CRL or CSR) to a text file.X509_TextDumpToString - Dumps details of X.509 certificate (or CRL or CSR) to a string.X509_ValidatePath - Validates a certificate path.Index: ASN.1 | Block Cipher | CMS | Conversion | Compression | CRL | ECC | General | Hash | HMAC | HPKE | KDF | OCSP | Padding | PBE | PEM files | PFX | PRF | Prompt | RNG | RSA Keys | RSA (Raw) | SIG | S/MIME | Triple DES (TDEA) | Wipe | X.509 Certificates | XOF
Dumps details of ASN.1 formatted data to a text file
Public Declare Function ASN1_TextDump Lib "diCrPKI.dll" (ByVal strFileOut As String, ByVal strFileOrPEMString As String, ByVal nOptions As Long) As Long
nRet = ASN1_TextDump(strFileOut, strFileOrPEMString, nOptions)
long __stdcall ASN1_TextDump(const char *szFileOut, const char *szFileOrPEMString, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
static int dipki::Asn1::TextDump (const std::string &outputFile, const std::string &asn1File, Opts opts=Opts::None)
static Asn1.text_dump(outputfile, asn1file, opts=0)
The input may be a binary file in BER/DER format or a text file in PEM or base64-encoded format, or may be passed as a base64 string or as a PEM string. Only data with an outer SEQUENCE is accepted, which is the rule for all common PKI-related ASN.1 files.
The output is a text file showing the structure of the ASN.1 formatted data.
All the bytes in the input are printed in hexadecimal form laid out to show the nested structure of the ASN.1 formatted data
together with comments beginning with "--" that give further details about the elements.
The length of each object is shown in bytes, for example
30 81 e0 --SEQUENCE/224 bytes
shows the tag (30) and length bytes (81 e0) which begin a SEQUENCE of length 224 bytes, equal to hexadecimal E0 bytes.
Use the PKI_ASN1_NOCOMMENTS option to hide the comments: the resulting hexadecimal output without comments should decode back
directly to the original binary file.
Dim nRet As Long Dim strInputFile As String Dim strOutFile As String strInputFile = "smallca.cer" strOutFile = "dumpasn1-smallca.cer.txt" Debug.Print "File: " & strInputFile nRet = ASN1_TextDump(strOutFile, strInputFile, 0) Debug.Print "ASN1_TextDump returns " & nRet ShowTextFile strOutFile ' Pass input as a string strInputFile = "MAQwAgUA" strOutFile = "dumpasn1.txt" Debug.Print "Input: " & strInputFile nRet = ASN1_TextDump(strOutFile, strInputFile, 0) Debug.Print "ASN1_TextDump returns " & nRet ShowTextFile strOutFile ' Again with no comments nRet = ASN1_TextDump(strOutFile, strInputFile, PKI_ASN1_NOCOMMENTS) Debug.Print "ASN1_TextDump returns " & nRet ShowTextFile strOutFile
File: smallca.cer
ASN1_TextDump returns 0
30 81 e0 --SEQUENCE/224 bytes
30 81 9a --SEQUENCE/154 bytes
02 01 --INTEGER/1 bytes
01
30 0d --SEQUENCE/13 bytes
06 09 --OBJECTIDENTIFIER/9 bytes
2a 86 48 86 f7 0d 01 01 05
--sha1WithRSAEncryption (1.2.840.113549.1.1.5)
05 00 --NULL/0 bytes
30 0c --SEQUENCE/12 bytes
31 0a --SET/10 bytes
30 08 --SEQUENCE/8 bytes
06 03 --OBJECTIDENTIFIER/3 bytes
55 04 03
--commonName (2.5.4.3)
13 01 --PRINTABLESTRING/1 bytes
41
--'A'
30 1e --SEQUENCE/30 bytes
17 0d --UTCTIME/13 bytes
39 39 30 39 31 39 30 31 30 38 34 37 5a
--'990919010847Z'
17 0d --UTCTIME/13 bytes
33 39 31 32 33 31 32 33 35 39 35 39 5a
--'391231235959Z'
30 0c --SEQUENCE/12 bytes
31 0a --SET/10 bytes
30 08 --SEQUENCE/8 bytes
06 03 --OBJECTIDENTIFIER/3 bytes
55 04 03
--commonName (2.5.4.3)
13 01 --PRINTABLESTRING/1 bytes
41
--'A'
30 4a --SEQUENCE/74 bytes
30 0d --SEQUENCE/13 bytes
06 09 --OBJECTIDENTIFIER/9 bytes
2a 86 48 86 f7 0d 01 01 01
--rsaEncryption (1.2.840.113549.1.1.1)
05 00 --NULL/0 bytes
03 39 --BITSTRING/57 bytes
00 --0 unused bits
--encapsulates:
30 36 --SEQUENCE/54 bytes
02 31 --INTEGER/49 bytes
02 f9 09 6a 7d 83 55 c2 71 ae f1 6a cb 45 41 ba
b3 22 a2 83 b5 ad de 70 e3 37 19 a7 c9 bb ee 76
4b e2 fc b8 5c c7 9b e2 3f 27 1f 6f b7 b5 36 80
19
02 01 --INTEGER/1 bytes
03
30 0d --SEQUENCE/13 bytes
06 09 --OBJECTIDENTIFIER/9 bytes
2a 86 48 86 f7 0d 01 01 05
--sha1WithRSAEncryption (1.2.840.113549.1.1.5)
05 00 --NULL/0 bytes
03 32 --BITSTRING/50 bytes
00 --0 unused bits
01 9a 9b b2 ec b9 cd fd 66 c6 94 5b 2e d6 96 dc
32 87 68 da 5e 6f 2e 5d 5a 7f e6 09 2e 60 8f 8c
45 a5 18 7e 06 1c e9 81 aa ea d6 f2 e3 14 7d 25
91
--(227 bytes)
Input: MAQwAgUA
ASN1_TextDump returns 0
30 04 --SEQUENCE/4 bytes
30 02 --SEQUENCE/2 bytes
05 00 --NULL/0 bytes
--(6 bytes)
ASN1_TextDump returns 0
30 04
30 02
05 00
ASN1_TextDumpToString ASN1_Type
Dumps details of ASN.1 formatted data to a string.
Public Declare Function ASN1_TextDumpToString Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strFileOrPEMString As String, ByVal strDirName As String, ByVal nOptions As Long) As Long
nRet = ASN1_TextDumpToString(strOutput, nOutChars, strFileOrPEMString, nOptions)
long __stdcall ASN1_TextDumpToString(char *szOutput, long nOutChars, const char *szFileOrPEMString, const char *szDirName, long nOptions);
"" for default = system TEMP directory.If successful, the return value is the number of characters in or required for the output string; otherwise it returns a nonzero error code.
Public Function asn1TextDumpToString (szFileOrPEMString As String, Optional nOptions As Long = 0, Optional szDirName As String = "") As String
static std::string dipki::Asn1::TextDumpToString (const std::string &asn1File, Opts opts=Opts::None)
static Asn1.text_dump_tostring(asn1file, opts=0)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The input may be a binary file in BER/DER format or a text file in PEM or base64-encoded format, or may be passed as a base64 string or as a PEM string. Only data with an outer SEQUENCE is accepted, which is the rule for all common PKI-related ASN.1 files.
The output is a text file showing the structure of the ASN.1 formatted data.
All the bytes in the input are printed in hexadecimal form laid out to show the nested structure of the ASN.1 formatted data
together with comments beginning with "--" that give further details about the elements.
The length of each object is shown in bytes, for example
30 81 e0 --SEQUENCE/224 bytes
shows the tag (30) and length bytes (81 e0) which begin a SEQUENCE of length 224 bytes, equal to hexadecimal E0 bytes.
Use the PKI_ASN1_NOCOMMENTS option to hide the comments: the resulting hexadecimal output without comments should decode back
directly to the original binary file.
This function creates a temporary file, by default in the system TEMP directory. This file is locked and is automatically deleted after use.
The user can specify a particular directory known to be secure if required. If the specified directory does not exist, the system TEMP directory will be used.
Dim strInputFile As String Dim strBuffer As String Dim nChars As Long ' Pass input as a string strInputFile = "MAQwAgUA" Debug.Print "Input: " & strInputFile ' Query for required length nChars = ASN1_TextDumpToString("", 0, strInputFile, "", 0) Debug.Print "ASN1_TextDumpToString returns " & nChars ' Dimension output buffer strBuffer = String(nChars, " ") nChars = ASN1_TextDumpToString(strBuffer, Len(strBuffer), strInputFile, "", 0) Debug.Print strBuffer ' Again with no comments strBuffer = String(nChars, " ") nChars = ASN1_TextDumpToString(strBuffer, Len(strBuffer), strInputFile, "", PKI_ASN1_NOCOMMENTS) Debug.Print "ASN1_TextDumpToString returns " & nChars Debug.Print Left(strBuffer, nChars)
Input: MAQwAgUA
ASN1_TextDumpToString returns 95
30 04 --SEQUENCE/4 bytes
30 02 --SEQUENCE/2 bytes
05 00 --NULL/0 bytes
--(6 bytes)
ASN1_TextDumpToString returns 30
30 04
30 02
05 00
Debug.Print x509TextDumpToString("AliceRSASignByCarl.cer")
Debug.Print x509QueryCert("AliceRSASignByCarl.cer", "subjectName")
Debug.Print asn1TextDumpToString("AliceRSASignByCarl.cer")
Dim strInput As String Dim strOutput As String strInput = "MAQwAgUA" Debug.Print "Input: " & strInput strOutput = asn1TextDumpToString(strInput) Debug.Print strOutput Debug.Print asn1TextDumpToString(strInput, PKI_ASN1_NOCOMMENTS)
Describes the type of ASN.1 data.
Public Declare Function ASN1_Type Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strFileOrPEMString As String, ByVal nOptions As Long) As Long
nRet = ASN1_Type(strOutput, nOutChars, strFileOrPEMString, nOptions)
long __stdcall ASN1_Type(char *szOutput, long nOutChars, const char *szFileOrPEMString, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function asn1Type (szFileOrPEMString As String, Optional nOptions As Long = 0) As String
static std::string dipki::Asn1::Type (const std::string &asn1File)
static Asn1.type(asn1file)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The input may be a binary file in BER/DER format or a text file in PEM or base64 format,
or may be passed as a base64 string or as a PEM string.
The output is a string describing the most likely type of the ASN.1-formatted data,
or an empty string ("") if the type cannot be determined.
The following types are detected:
| Output string value | ASN.1 object type | Reference |
|---|---|---|
| EC PRIVATE KEY | ECPrivateKey | [RFC5915] |
| OCSP REQUEST | OCSPRequest | [RFC6960] |
| OCSP RESPONSE | OCSPResponse | [RFC6960] |
| PKCS1 RSA PRIVATE KEY | RSAPrivateKey | [RFC3447] |
| PKCS1 RSA PUBLIC KEY | RSAPublicKey | [RFC3447] |
| PKCS10 CERTIFICATE REQUEST | CertificationRequest | [RFC2986] |
| PKCS12 PFX | PFX | [RFC7292] |
| PKCS7 CERTIFICATE CHAIN | ContentInfo | [RFC5652] |
| PKCS7/CMS COMPRESSED DATA | ContentInfo | [RFC3274] |
| PKCS7/CMS DATA | ContentInfo | [RFC5652] |
| PKCS7/CMS ENVELOPED DATA | ContentInfo | [RFC5652] |
| CMS AUTH ENVELOPED DATA | ContentInfo | [RFC5083] |
| PKCS7/CMS SIGNED DATA | ContentInfo | [RFC5652] |
| PKCS8 ENCRYPTED PRIVATE KEY | EncryptedPrivateKeyInfo | [RFC5208], [RFC5958] |
| PKCS8 PRIVATE KEY INFO | PrivateKeyInfo | [RFC5208], [RFC5958] |
| PKCS8 ONE ASYMMETRIC KEY | OneAsymmetricKey | [RFC5958] |
| PUBLIC KEY INFO | SubjectPublicKeyInfo | [RFC3279], [RFC5480] |
| X509 CERTIFICATE | Certificate | [RFC5280] |
| X509 CRL | CertificateList | [RFC5280] |
Note that these descriptions are not necessarily those used as labels for PEM formatted files. See PEM_FileFromBinFile and [RFC7468].
Dim nChars As Long Dim strTypeName As String ' Output guaranteed not to be longer than PKI_ASN1_TYPE_MAXCHARS characters strTypeName = String(PKI_ASN1_TYPE_MAXCHARS, " ") nChars = ASN1_Type(strTypeName, Len(strTypeName), "AliceRSASignByCarl.cer", 0) If nChars > 0 Then Debug.Print Left(strTypeName, nChars) strTypeName = String(PKI_ASN1_TYPE_MAXCHARS, " ") nChars = ASN1_Type(strTypeName, Len(strTypeName), "AlicePrivRSASign.pri", 0) If nChars > 0 Then Debug.Print Left(strTypeName, nChars) strTypeName = String(PKI_ASN1_TYPE_MAXCHARS, " ") nChars = ASN1_Type(strTypeName, Len(strTypeName), "BobPrivRSAEncrypt.p8e", 0) If nChars > 0 Then Debug.Print Left(strTypeName, nChars) strTypeName = String(PKI_ASN1_TYPE_MAXCHARS, " ") nChars = ASN1_Type(strTypeName, Len(strTypeName), "rfc3280bis_CRL.crl", 0) If nChars > 0 Then Debug.Print Left(strTypeName, nChars)
X509 CERTIFICATE PKCS8 PRIVATE KEY INFO PKCS8 ENCRYPTED PRIVATE KEY X509 CRL
Debug.Print asn1Type("AliceRSASignByCarl.cer", 0) Debug.Print asn1Type("BobPrivRSAEncrypt.p8e", 0) Debug.Print asn1Type("bad.file", 0)
ASN1_TextDump PEM_FileFromBinFile
Encrypt or decrypt data in a byte array. The key and initialization vector are given as byte arrays.
@deprecated
Use CIPHER_EncryptBytes or CIPHER_DecryptBytes instead.
Public Declare Function CIPHER_Bytes Lib "diCrPKI.dll"
(ByVal fEncrypt As Long, ByRef lpOutput As Byte, ByRef lpData As Byte, ByVal nDataLen As Long,
ByRef lpKey As Byte, ByRef lpIV As Byte,
ByVal strAlgAndMode As String, ByVal nOptions As Long) As Long
nRet = CIPHER_Bytes(fEncrypt, lpOutput(0), lpData(0), nDataLen, lpKey(0),
lpIV(0), strAlgAndMode, nOptions) ' Note the "(0)" after the byte array parameters
long __stdcall CIPHER_Bytes(long fEncrypt, unsigned char *lpOutput, const unsigned char *lpData, long nDataLen, const unsigned char *lpKey, const unsigned char *lpIV, const char *szAlgAndMode, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Cipher.Encrypt Method (Byte[], Byte[], Byte[], CipherAlgorithm, Mode)
Cipher.Decrypt Method (Byte[], Byte[], Byte[], CipherAlgorithm, Mode)
The algorithm and mode must be specified using either the szAlgAndMode or nOptions parameter (see Specifying the algorithm and mode for generic block cipher functions). The length of key lpKey must be exactly the required key size, and the length of the IV, if required, exactly the block size. See Valid key and block sizes. Important: The output array lpOutput must be at least nDataLen bytes long. lpOutput and lpData may be the same.
For ECB and CBC modes, the length of the input data lpInput must be an exact multiple
of the block size otherwise a BAD_LENGTH_ERROR error will result.
It is the responsibility of the user to provide suitable padding before encrypting in those modes
and to remove any padding after decrypting.
Note that we convert the input data from hex strings to byte arrays in this example just for convenience so we can quickly demonstrate how the function works. In practice, since you are using the "Bytes" function, we assume your input data would already be in byte array form. If all your data strings are already in hex string format and you want the output in hex, then use CIPHER_Hex instead.
Dim nRet As Long Dim strOutput As String Dim strInput As String Dim sCorrect As String Dim abKey() As Byte Dim abInitV() As Byte Dim abResult() As Byte Dim abData() As Byte Dim abCheck() As Byte Dim nDataLen As Long ' Set up input in byte arrays strInput = "Now is the time for all good men" sCorrect = "C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E177" abKey = cnvBytesFromHexStr("0123456789ABCDEFF0E1D2C3B4A59687") abInitV = cnvBytesFromHexStr("FEDCBA9876543210FEDCBA9876543210") abData = StrConv(strInput, vbFromUnicode) nDataLen = UBound(abData) - LBound(abData) + 1 ' Pre-dimension output array ReDim abResult(nDataLen - 1) Debug.Print "KY=" & cnvHexStrFromBytes(abKey) Debug.Print "IV=" & cnvHexStrFromBytes(abInitV) Debug.Print "PT=" & strInput Debug.Print "PT=" & cnvHexStrFromBytes(abData) ' Encrypt in one-off process (abResult <-- abData) nRet = CIPHER_Bytes(ENCRYPT, abResult(0), abData(0), nDataLen, _ abKey(0), abInitV(0), "aes128-cbc", 0) Debug.Print "CIPHER_Bytes(ENCRYPT) returns " & nRet Debug.Print "CT=" & cnvHexStrFromBytes(abResult) Debug.Print "OK=" & sCorrect ' Now decrypt back (abCheck <-- abResult) ReDim abCheck(nDataLen - 1) nRet = CIPHER_Bytes(DECRYPT, abCheck(0), abResult(0), nDataLen, _ abKey(0), abInitV(0), "", PKI_BC_AES128 + PKI_MODE_CBC) Debug.Print "CIPHER_Bytes(DECRYPT) returns " & nRet ' And decode back from a byte array into a string Debug.Print "P'=" & cnvHexStrFromBytes(abCheck) strOutput = StrConv(abCheck(), vbUnicode) Debug.Print "P'=" & strOutput
This should result in output as follows:
KY=0123456789ABCDEFF0E1D2C3B4A59687 IV=FEDCBA9876543210FEDCBA9876543210 PT=Now is the time for all good men PT=4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E CIPHER_Bytes(ENCRYPT) returns 0 CT=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E177 OK=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E177 CIPHER_Bytes(DECRYPT) returns 0 P'=4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E P'=Now is the time for all good men
Decrypt data using an authenticated encryption algorithm.
Public Declare Function CIPHER_DecryptAEAD Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpInput As Byte, ByVal nInputLen As Long, ByRef lpKey As Byte, ByVal nKeyLen As Long, ByRef lpIV As Byte, ByVal nIvLen As Long, ByRef lpAAD As Byte, ByVal nAadLen As Long, ByVal nOptions As Long) As Long
nRet = CIPHER_DecryptAEAD(lpOutput(0), nOutBytes, lpInput(0), nInputLen, lpKey(0), nKeylen, lpIV(0), nIvLen, lpAAD(0), nAadLen, nOptions)
long __stdcall CIPHER_DecryptAEAD(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpInput, long nInputLen, const unsigned char *lpKey, long nKeyLen, const unsigned char *lpIV, long nIvLen, const unsigned char *lpAAD, long nAadLen, long nOptions);
AEAD_AES_128_GCM authenticated encryption algorithm from RFC 5116AEAD_AES_256_GCM authenticated encryption algorithm from RFC 5116AES-192-GCM authenticated encryption algorithm in the same mannerIf successful, the return value is the number of bytes required in the output; otherwise it returns a negative error code.
Public Function cipherDecryptAEAD (lpInput() As Byte, lpKey() As Byte, lpIV() As Byte, lpAAD() As Byte, nOptions As Long) As Byte()
Cipher.DecryptAEAD Method (Byte[], Byte[], Byte[], AeadAlgorithm)
Cipher.DecryptAEAD Method (Byte[], Byte[], Byte[], Byte[], AeadAlgorithm, Cipher.Opts)
static bvec_t dipki::Cipher::DecryptAEAD (const bvec_t &input, const bvec_t &key, const bvec_t &iv, AeadAlg aeadAlg, Opts opts=Opts::None, const bvec_t &aad=bvec_t())
static Cipher.decrypt_aead(data, key, iv, aeadalg, aad=None, opts=Opts.DEFAULT)
The input is expected to be the ciphertext with a 16-byte tag appended ciphertext||Tag, or, if the PKI_IV_PREFIX option is set,
then the same but with the 12-byte IV prepended IV||ciphertext||Tag, where || denotes concatenation.
If the IV is not prepended to the input, then it must be provided in the lpIV argument.
Note that the term "IV" is used here to mean exactly the same as "nonce".
The length of key lpKey must be exactly the required key size in bytes: 16 for PKI_AEAD_AES_128_GCM, 24 for PKI_AEAD_AES_192_GCM, or 32 for PKI_AEAD_AES_256_GCM. It is an error if a PKI_AEAD_ option is not provided in the nOptions argument. In all cases the IV must be exactly 12 bytes (96 bits) and the tag must be exactly 16 bytes (128 bits). If additional authentication data (AAD) was provided during encryption then the exact same AAD data must be provided here.
If nOutBytes is set to zero or lpOutput set to 0 (or NULL in C or ByVal 0& in VBA),
the required number of bytes will be returned.
This will be either exactly 16 bytes shorter than the length of the input, or exactly 28 bytes shorter if the PKI_IV_PREFIX option is used.
The output buffer lpOutput must not be the same as or overlap with the input lpInput.
Dim key() As Byte Dim iv() As Byte Dim pt() As Byte Dim ct() As Byte Dim strOK As String Dim ptlen As Long Dim ctlen As Long Dim keylen As Long Dim ivlen As Long ' GCM Test Case #03 (AES-128) key = cnvBytesFromHexStr("feffe9928665731c6d6a8f9467308308") iv = cnvBytesFromHexStr("cafebabefacedbaddecaf888") ct = cnvBytesFromHexStr("42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4") strOK = "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255" keylen = UBound(key) + 1 ivlen = UBound(iv) + 1 ctlen = UBound(ct) + 1 Debug.Print "KY=" & cnvHexStrFromBytes(key) Debug.Print "IV=" & cnvHexStrFromBytes(iv) Debug.Print "CT=" & cnvHexStrFromBytes(ct) ' 1. Find out required output length ptlen = CIPHER_DecryptAEAD(ByVal 0&, 0, ct(0), ctlen, key(0), keylen, iv(0), ivlen, ByVal 0&, 0, PKI_AEAD_AES_128_GCM) Debug.Print "CIPHER_DecryptAEAD returns " & ptlen ' 1a. Cope with error If (ptlen < 0) Then Debug.Print pkiErrorLookup(ptlen) Exit Sub End If ' 2. Allocate the output buffer, coping with possible zero-length output, then decrypt pt = vbNullString ' Default empty array If ptlen > 0 Then ReDim pt(ptlen - 1) ptlen = CIPHER_DecryptAEAD(pt(0), ptlen, ct(0), ctlen, key(0), keylen, iv(0), ivlen, ByVal 0&, 0, PKI_AEAD_AES_128_GCM) End If Debug.Print "PT=" & cnvHexStrFromBytes(pt) Debug.Print "OK=" & strOK
This should result in output as follows:
KY=FEFFE9928665731C6D6A8F9467308308 IV=CAFEBABEFACEDBADDECAF888 CT=42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E091473F59854D5C2AF327CD64A62CF35ABD2BA6FAB4 CIPHER_DecryptAEAD returns 64 PT=D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A721C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B391AAFD255 OK=d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255
Dim key() As Byte Dim iv() As Byte Dim pt() As Byte Dim ct() As Byte Dim strOK As String Dim ptlen As Long Dim ctlen As Long Dim keylen As Long Dim ivlen As Long ' GCM Test Case #03 (AES-128) key = cnvBytesFromHexStr("feffe9928665731c6d6a8f9467308308") iv = cnvBytesFromHexStr("cafebabefacedbaddecaf888") ct = cnvBytesFromHexStr("42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4") strOK = "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255" keylen = UBound(key) + 1 ivlen = UBound(iv) + 1 ctlen = UBound(ct) + 1 Debug.Print "KY=" & cnvHexStrFromBytes(key) Debug.Print "IV=" & cnvHexStrFromBytes(iv) Debug.Print "CT=" & cnvHexStrFromBytes(ct) ' 1. Find out required output length ptlen = CIPHER_DecryptAEAD(ByVal 0&, 0, ct(0), ctlen, key(0), keylen, iv(0), ivlen, ByVal 0&, 0, PKI_AEAD_AES_128_GCM) Debug.Print "CIPHER_DecryptAEAD returns " & ptlen ' 1a. Cope with error If (ptlen < 0) Then Debug.Print pkiErrorLookup(ptlen) Exit Sub End If ' 2. Allocate the output buffer, coping with possible zero-length output, then decrypt pt = vbNullString ' Default empty array If ptlen > 0 Then ReDim pt(ptlen - 1) ptlen = CIPHER_DecryptAEAD(pt(0), ptlen, ct(0), ctlen, key(0), keylen, iv(0), ivlen, ByVal 0&, 0, PKI_AEAD_AES_128_GCM) End If Debug.Print "PT=" & cnvHexStrFromBytes(pt) Debug.Print "OK=" & strOK ' II.Using New wrapper ' Must dimension any optional empty byte array Dim lpAAD() As Byte pt = cipherDecryptAEAD(ct, key, iv, lpAAD, PKI_AEAD_AES_128_GCM) Debug.Print "PT=" & cnvHexStrFromBytes(pt)
Dim key() As Byte Dim iv() As Byte Dim pt() As Byte Dim ct() As Byte Dim strOK As String ' GCM Test Case #03 (AES-128) key = cnvBytesFromHexStr("feffe9928665731c6d6a8f9467308308") iv = cnvBytesFromHexStr("cafebabefacedbaddecaf888") ct = cnvBytesFromHexStr("42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4") strOK = "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255" Dim lpAAD() As Byte ' Declare empty array for NULL input pt = cipherDecryptAEAD(ct, key, iv, lpAAD, PKI_AEAD_AES_128_GCM) Debug.Print "PT=" & cnvHexStrFromBytes(pt) Debug.Print "OK=" & strOK
Decrypt data in a byte array using the specified block cipher algorithm, mode and padding. The key and initialization vector are passed as byte arrays.
Public Declare Function CIPHER_DecryptBytes Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpInput As Byte, ByVal nInputLen As Long, ByRef lpKey As Byte, ByVal nKeyLen As Long, ByRef lpIV As Byte, ByVal nIvLen As Long, ByVal strAlgModePad As String, ByVal nOptions As Long) As Long
nRet = CIPHER_DecryptBytes(lpOutput(0), nOutBytes, lpInput(0), nInputLen, lpKey(0), nKeyLen, lpIV(0), nIvLen, strAlgModePad, nOptions)
long __stdcall CIPHER_DecryptBytes(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpInput, long nInputLen, const unsigned char *lpKey, long nKeyLen, const unsigned char *lpIV, long nIvLen, const char *szAlgModePad, long nOptions);
NULL for ECB mode.If successful, the return value is the number of bytes in or required in the output; otherwise it returns a negative error code.
Public Function cipherDecryptBytes (lpInput() As Byte, lpKey() As Byte, lpIV() As Byte, szAlgModePad As String, Optional nOptions As Long = 0) As Byte()
Cipher.Decrypt Method (Byte[], Byte[], Byte[], CipherAlgorithm, Mode, Padding, Cipher.Opts)
static bvec_t dipki::Cipher::Decrypt (const bvec_t &data, const bvec_t &key, const bvec_t &iv, Alg alg, Mode mode=Mode::ECB, Padding pad=Padding::Default, Opts opts=Opts::None)
static bvec_t dipki::Cipher::Decrypt (const bvec_t &data, const bvec_t &key, const bvec_t &iv, const std::string algModePad, Opts opts=Opts::None)
static Cipher.decrypt_block(data, key, iv=None, alg=Alg.TDEA, mode=Mode.ECB)
static Cipher.decrypt(data, key, iv=None, algmodepad='', alg=None, mode=Mode.ECB, pad=Pad.DEFAULT, opts=Opts.DEFAULT)
static Cipher.decrypt_block(data, key, iv=None, alg=Alg.TDEA, mode=Mode.ECB)
The algorithm/mode/padding must be specified using either the szAlgModePad string or nOptions parameter, but not both (see Specifying the algorithm, mode and padding for generic block cipher functions). The length of key lpKey must be exactly the required key size, and the length of the IV, if required, exactly the block size. See Valid key and block sizes.
[New in v12.3] You can find the required output length in bytes by setting
nOutBytes to zero or lpOutput to 0 (or NULL in C or ByVal 0& in VBA).
For ECB and CBC cipher modes, the return value is now (as of [v12.3]) the exact length of plaintext after padding has been removed.
NULL to find the exact decrypted length.
It is an error (DECRYPT_ERROR) if the padding bytes after decryption are not as expected according to the padding method specified.
If the cipher mode is ECB or CBC, it is an error (BAD_LENGTH_ERROR)
if the length of the input is not an exact multiple of the block size.
The input buffer lpInput may point to the same location as the output buffer.
If so, the input ciphertext data will be overwritten by the output (and the user must truncate to remove any padding bytes).
Defaults: If padding is not specified then the default padding method depends on the cipher mode:
pkcs5padding will be used for ECB and CBC mode and nopadding for all other modes.
The default cipher mode is ECB.
Thus "aes128" is the same as "aes128/ecb/pkcs5padding".
Dim key() As Byte Dim iv() As Byte Dim ct() As Byte Dim ok() As Byte Dim dt() As Byte Dim ctlen As Long Dim dtlen As Long Dim keylen As Long Dim ivlen As Long Dim algstr As String ' INPUT for known test vector algstr = "Aes128/CBC/OneAndZeroes" Debug.Print algstr key = cnvBytesFromHexStr("0123456789ABCDEFF0E1D2C3B4A59687") iv = cnvBytesFromHexStr("FEDCBA9876543210FEDCBA9876543210") keylen = UBound(key) + 1 ivlen = UBound(iv) + 1 Debug.Print ("KY=" & cnvHexStrFromBytes(key)) Debug.Print ("IV=" & cnvHexStrFromBytes(iv)) ct = cnvBytesFromHexStr("C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B") ctlen = UBound(ct) + 1 Debug.Print ("CT=" & cnvHexStrFromBytes(ct)) ' OK = "Now is the time for all good men to" ok = cnvBytesFromHexStr("4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F") ' DECRYPT - OLD METHOD Debug.Print "Decrypt - old method with truncation" ' 1. Set output buffer to same length as input (final output will always be shorter for CBC mode) dtlen = ctlen ReDim dt(dtlen - 1) ' 2. Perform decryption including padding into output buffer dtlen = CIPHER_DecryptBytes(dt(0), dtlen, ct(0), ctlen, key(0), keylen, iv(0), ivlen, algstr, 0) Debug.Print "CIPHER_DecryptBytes returns " & dtlen Debug.Assert dtlen > 0 ' 3. Re-dimension the output to the correct length ReDim Preserve dt(dtlen - 1) Debug.Print ("DT=" & cnvHexStrFromBytes(dt)) Debug.Print ("DT='" & StrConv(dt, vbUnicode) + "'") ' DECRYPT - NEW METHOD [v12.3] Debug.Print "Decrypt - new method with exact length" ' 1. Find exact output length using null/zero-length output dtlen = CIPHER_DecryptBytes(ByVal 0&, 0, ct(0), ctlen, key(0), keylen, iv(0), ivlen, algstr, 0) Debug.Print "CIPHER_DecryptBytes(NULL) returns " & dtlen Debug.Assert dtlen > 0 ' 2. Dimension output buffer to exact length ReDim dt(dtlen - 1) ' 3. Perform decryption - no need to truncate dtlen = CIPHER_DecryptBytes(dt(0), dtlen, ct(0), ctlen, key(0), keylen, iv(0), ivlen, algstr, 0) Debug.Print "CIPHER_DecryptBytes returns " & dtlen Debug.Assert dtlen > 0 Debug.Print ("DT=" & cnvHexStrFromBytes(dt)) Debug.Print ("DT='" & StrConv(dt, vbUnicode) + "'") Debug.Print "Check actual padding by decrypting with NoPadding..." algstr = "Aes128/CBC/NoPadding" Debug.Print algstr dtlen = ctlen ReDim dt(dtlen - 1) dtlen = CIPHER_DecryptBytes(dt(0), dtlen, ct(0), ctlen, key(0), keylen, iv(0), ivlen, algstr, 0) Debug.Print "CIPHER_DecryptBytes(NoPadding) returns " & dtlen Debug.Print ("DT=" & cnvHexStrFromBytes(dt))
This should result in output as follows:
Aes128/CBC/OneAndZeroes KY=0123456789ABCDEFF0E1D2C3B4A59687 IV=FEDCBA9876543210FEDCBA9876543210 CT=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B Decrypt - old method with truncation CIPHER_DecryptBytes returns 35 DT=4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F DT='Now is the time for all good men to' Decrypt - new method with exact length CIPHER_DecryptBytes(NULL) returns 35 CIPHER_DecryptBytes returns 35 DT=4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F DT='Now is the time for all good men to' Check actual padding by decrypting with NoPadding... Aes128/CBC/NoPadding CIPHER_DecryptBytes(NoPadding) returns 48 DT=4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F80000000000000000000000000
Example 2: showing use of PKI_IV_PREFIX to prepend the IV before the ciphertext in the output.
Dim strCipherValue As String Dim strPlain As String Dim pt() As Byte Dim ptlen As Long Dim ct() As Byte Dim ctlen As Long Dim key() As Byte Dim keylen As Long Dim iv() As Byte Dim ivlen As Long Dim nRet As Long Dim strDT As String Dim dt() As Byte Dim dtlen As Long ' The plaintext to encrypt... strPlain = "<encryptme>hello world</encryptme>" Debug.Print "PT='" & strPlain & "'" ' We need this as a byte array... pt = StrConv(strPlain, vbFromUnicode) Debug.Print "HEX(PT)=" & cnvHexStrFromBytes(pt) ptlen = UBound(pt) + 1 Debug.Print "Len(PT)=" & ptlen ' 128-bit AES key ' (Usually generated at random but here we use a fixed test one) key = cnvBytesFromHexStr("6162636465666768696A6B6C6D6E6F70") keylen = UBound(key) + 1 Debug.Print "HEX(KEY)=" & cnvHexStrFromBytes(key) ' Generate a random 128-bit IV for AES encryption ivlen = PKI_BLK_AES_BYTES ReDim iv(ivlen - 1) nRet = RNG_Bytes(iv(0), ivlen, "", 0) Debug.Print "HEX(IV)=" & cnvHexStrFromBytes(iv) ' Encrypt using AES-128 with IV prefixed to ciphertext ' How many bytes in the encrypted output? ctlen = CIPHER_EncryptBytes(ByVal 0&, 0, pt(0), ptlen, key(0), keylen, iv(0), ivlen, "aes128/cbc/pkcs5", PKI_IV_PREFIX) Debug.Print "Len(IV|CT)=" & ctlen Debug.Assert (ctlen > 0) ' Allocate the buffer ReDim ct(ctlen - 1) ' Encrypt to output buffer ctlen = CIPHER_EncryptBytes(ct(0), ctlen, pt(0), ptlen, key(0), keylen, iv(0), ivlen, "aes128/cbc/pkcs5", PKI_IV_PREFIX) Debug.Assert (ctlen > 0) Debug.Print "IV|CT=" & cnvHexStrFromBytes(ct) ' Encode CT using base64 strCipherValue = cnvB64StrFromBytes(ct) ' Output the CipherValue element ' (Note this will be different each time) Debug.Print "<CipherValue>" & strCipherValue & "</CipherValue>" ' ------------------------------------------ ' PART 2 - decrypt the given ciphertext Debug.Print Debug.Print "DECRYPTING..." ' INPUT: strCipherValue, key ' Decode base64 to byte array ct = cnvBytesFromB64Str(strCipherValue) ctlen = UBound(ct) + 1 Debug.Print "IV|CT=" & cnvHexStrFromBytes(ct) ' Find decrypted output length - new behaviour in [v12.3] (previously needed to truncate) dtlen = CIPHER_DecryptBytes(ByVal 0&, 0, ct(0), ctlen, key(0), keylen, ByVal 0&, 0, "aes128/cbc/pkcs5", PKI_IV_PREFIX) Debug.Assert (dtlen > 0) ReDim dt(dtlen - 1) ' Note we don't need to specify the IV: it is included in the prefix dtlen = CIPHER_DecryptBytes(dt(0), dtlen, ct(0), ctlen, key(0), keylen, ByVal 0&, 0, "aes128/cbc/pkcs5", PKI_IV_PREFIX) Debug.Print "Len(DT)=" & dtlen Debug.Assert (dtlen >= 0) Debug.Print "DT=" & cnvHexStrFromBytes(dt) ' Convert from bytes to string strDT = StrConv(dt, vbUnicode) Debug.Print "DT='" & strDT & "'"
PT='<encryptme>hello world</encryptme>' HEX(PT)=3C656E63727970746D653E68656C6C6F20776F726C643C2F656E63727970746D653E Len(PT)=34 HEX(KEY)=6162636465666768696A6B6C6D6E6F70 HEX(IV)=556DA05DF58DE51874B032768BA99A26 Len(IV|CT)=64 IV|CT=556DA05DF58DE51874B032768BA99A26884B6CD2045916D7F1D8D88E6BB8F5520C69479D352701BBBA2E67DE03DF0319B3C83EA90093AC6C77E4709A26B46E80 <CipherValue>VW2gXfWN5Rh0sDJ2i6maJohLbNIEWRbX8djYjmu49VIMaUedNScBu7ouZ94D3wMZs8g+qQCTrGx35HCaJrRugA==</CipherValue> DECRYPTING... IV|CT=556DA05DF58DE51874B032768BA99A26884B6CD2045916D7F1D8D88E6BB8F5520C69479D352701BBBA2E67DE03DF0319B3C83EA90093AC6C77E4709A26B46E80 Len(DT)=34 DT=3C656E63727970746D653E68656C6C6F20776F726C643C2F656E63727970746D653E DT='<encryptme>hello world</encryptme>'
See example for VBA wrapper cipherEncryptBytes in CIPHER_EncryptBytes.
@deprecated use CIPHER_DecryptBytes.
Decrypt data using the specified block cipher algorithm, mode and padding. The input data, key and initialization vector are all represented as hexadecimal strings.
Public Declare Function CIPHER_DecryptHex Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strInputHex As String, ByVal strKeyHex As String, ByVal strIvHex As String, ByVal strAlgModePad As String, ByVal nOptions As Long) As Long
nRet = CIPHER_DecryptHex(strOutput, nOutChars, strInputHex, strKeyHex, strIvHex, strAlgModePad, nOptions)
long __stdcall CIPHER_DecryptHex(char *szOutput, long nOutChars, const char *szInputHex, const char *szKeyHex, const char *szIvHex, const char *szAlgModePad, long nOptions);
"").If successful, the return value is the number of characters in or required in the output; otherwise it returns a nonzero error code.
Public Function cipherDecryptHex (szInputHex As String, szKeyHex As String, szIvHex As String, szAlgModePad As String, Optional nOptions As Long = 0) As String
Cipher.Decrypt Method (String, String, String, CipherAlgorithm, Mode, Padding, Cipher.Opts)
static Cipher.decrypt_hex(datahex, keyhex, ivhex='', algmodepad='', alg=None, mode=Mode.ECB, pad=Pad.DEFAULT, opts=Opts.DEFAULT)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
This is the equivalent of CIPHER_DecryptBytes with all parameters passed as hex-encoded strings instead of byte arrays.
It is similar to the CIPHER_Hex function except this accepts variable-length input and copes with padding if required, as well as the option to prepend the IV to the ciphertext.
Any padding will be removed after decryption. If the PKI_IV_PREFIX option is used, the IV will be expected prepended to the ciphertext in the input.
The algorithm/mode/padding must be specified using either the szAlgModePad string or nOptions parameter, but not both (see Specifying the algorithm, mode and padding for generic block cipher functions).
It is an error (BAD_PARAM_ERROR) to pass the empty string "" as input in szInputHex.
The output buffer strOutput should not be the same as the input strInputHex.
CAUTION: be aware of the special case where the output is the empty string "" of length zero.
Dim strKey As String Dim strIV As String Dim strPlain As String Dim strCipher As String Dim strOK As String Dim strAlg As String Dim nChars As Long strAlg = "Aes128/CBC/OneAndZeroes" Debug.Print strAlg strKey = "0123456789ABCDEFF0E1D2C3B4A59687" strIV = "FEDCBA9876543210FEDCBA9876543210" Debug.Print "KY=" & strKey Debug.Print "IV=" & strIV strCipher = "C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B" Debug.Print "CT=" & strCipher ' Correct result strOK = "4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F" ' 1. Find out how long an output buffer we need nChars = CIPHER_DecryptHex(vbNullString, 0, strCipher, strKey, strIV, strAlg, 0) Debug.Print "CIPHER_DecryptHex returns " & nChars Debug.Assert nChars > 0 ' 2. Allocate the buffer strPlain = String(nChars, " ") ' 3. Decrypt to output buffer nChars = CIPHER_DecryptHex(strPlain, nChars, strCipher, strKey, strIV, strAlg, 0) Debug.Print "PT=" & strPlain Debug.Print "OK=" & strOK ' PART 2 - CT includes IV prefix strCipher = "FEDCBA9876543210FEDCBA9876543210C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B" Debug.Print "IV||CT=" & strCipher nChars = CIPHER_DecryptHex(vbNullString, 0, strCipher, strKey, strIV, strAlg, PKI_IV_PREFIX) Debug.Print "CIPHER_DecryptHex(PKI_IV_PREFIX) returns " & nChars Debug.Assert nChars > 0 strPlain = String(nChars, " ") nChars = CIPHER_DecryptHex(strPlain, nChars, strCipher, strKey, strIV, strAlg, PKI_IV_PREFIX) Debug.Print "PT=" & strPlain Debug.Print "PT='" & cnvStringFromHexStr(strPlain) & "'"
This should result in output as follows:
Aes128/CBC/OneAndZeroes KY=0123456789ABCDEFF0E1D2C3B4A59687 IV=FEDCBA9876543210FEDCBA9876543210 CT=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B CIPHER_DecryptHex returns 70 PT=4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F OK=4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F IV||CT=FEDCBA9876543210FEDCBA9876543210C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B CIPHER_DecryptHex(PKI_IV_PREFIX) returns 70 PT=4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F PT='Now is the time for all good men to'
Dim strKeyHex As String
Dim strIvHex As String
Dim strPlainHex As String
Dim strCipherHex As String
strKeyHex = "0123456789ABCDEFF0E1D2C3B4A59687"
strIvHex = "FEDCBA9876543210FEDCBA9876543210"
strCipherHex = "C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B"
strPlainHex = cipherDecryptHex(strCipherHex, strKeyHex, strIvHex, "Aes128/CBC/OneAndZeroes")
Debug.Print "PT=" & strPlainHex
Debug.Print "PT='" & cnvStringFromHexStr(strPlainHex) & "'"
Encrypt data using an authenticated encryption algorithm.
Public Declare Function CIPHER_EncryptAEAD Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpInput As Byte, ByVal nInputLen As Long, ByRef lpKey As Byte, ByVal nKeyLen As Long, ByRef lpIV As Byte, ByVal nIvLen As Long, ByRef lpAAD As Byte, ByVal nAadLen As Long, ByVal nOptions As Long) As Long
nRet = CIPHER_EncryptAEAD(lpOutput(0), nOutBytes, lpInput(0), nInputLen, lpKey(0), nKeylen, lpIV(0), nIvLen, lpAAD(0), nAadLen, nOptions)
long __stdcall CIPHER_EncryptAEAD(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpInput, long nInputLen, const unsigned char *lpKey, long nKeyLen, const unsigned char *lpIV, long nIvLen, const unsigned char *lpAAD, long nAadLen, long nOptions);
AEAD_AES_128_GCM authenticated encryption algorithm from RFC 5116AEAD_AES_256_GCM authenticated encryption algorithm from RFC 5116AES-192-GCM authenticated encryption algorithm in the same mannerIf successful, the return value is the number of bytes required in the output; otherwise it returns a negative error code.
Public Function cipherEncryptAEAD (lpInput() As Byte, lpKey() As Byte, lpIV() As Byte, lpAAD() As Byte, nOptions As Long) As Byte()
Cipher.EncryptAEAD Method (Byte[], Byte[], Byte[], AeadAlgorithm)
Cipher.EncryptAEAD Method (Byte[], Byte[], Byte[], Byte[], AeadAlgorithm, Cipher.Opts)
static bvec_t dipki::Cipher::EncryptAEAD (const bvec_t &input, const bvec_t &key, const bvec_t &iv, AeadAlg aeadAlg, Opts opts=Opts::None, const bvec_t &aad=bvec_t())
static Cipher.encrypt_aead(data, key, iv, aeadalg, aad=None, opts=Opts.DEFAULT)
This function carries out authenticated encryption using AES-GCM. In this implementation, the function must have a fixed-length nonce (IV) of exactly 12 bytes (96 bits) and only creates a fixed-length tag of exactly 16 bytes (128 bits). There is no option to use different lengths for the IV or tag. The tag is automatically appended to the output of the encryption operation. The IV may optionally be prepended to the output using the PKI_IV_PREFIX option flag. Note that the term "IV" is used here to mean exactly the same as "nonce".
The length of key lpKey must be exactly the required key size in bytes: 16 for PKI_AEAD_AES_128_GCM, 24 for PKI_AEAD_AES_192_GCM, or 32 for PKI_AEAD_AES_256_GCM. It is an error if a PKI_AEAD_ option is not provided in the nOptions argument. The length of the IV must be exactly 12 bytes. The user is responsible for providing a unique IV each time the same key is used. Be aware it is a serious security risk if the same IV and key are used to encrypt different plaintexts.
If nOutBytes is set to zero or lpOutput set to 0 (or NULL in C or ByVal 0& in VBA),
the required number of bytes will be returned.
This will be either exactly 16 bytes longer than the length of the input, or exactly 28 bytes longer if the PKI_IV_PREFIX option is used.
The output buffer lpOutput must not be the same as or overlap with the input lpInput.
Dim key() As Byte Dim iv() As Byte Dim pt() As Byte Dim ct() As Byte Dim strOK As String Dim ptlen As Long Dim ctlen As Long Dim keylen As Long Dim ivlen As Long ' GCM Test Case #03 (AES-128) key = cnvBytesFromHexStr("feffe9928665731c6d6a8f9467308308") iv = cnvBytesFromHexStr("cafebabefacedbaddecaf888") pt = cnvBytesFromHexStr("d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255") strOK = "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4" keylen = UBound(key) + 1 ivlen = UBound(iv) + 1 ptlen = UBound(pt) + 1 Debug.Print "KY=" & cnvHexStrFromBytes(key) Debug.Print "IV=" & cnvHexStrFromBytes(iv) Debug.Print "PT=" & cnvHexStrFromBytes(pt) ' 1. Find out how long an output buffer we need ctlen = CIPHER_EncryptAEAD(ByVal 0&, 0, pt(0), ptlen, key(0), keylen, iv(0), ivlen, ByVal 0&, 0, PKI_AEAD_AES_128_GCM) Debug.Print "CIPHER_EncryptAEAD returns " & ctlen Debug.Assert ctlen > 0 ' 2. Allocate the buffer ReDim ct(ctlen - 1) ' 3. Encrypt to output buffer (NB tag is appended to the end) ctlen = CIPHER_EncryptAEAD(ct(0), ctlen, pt(0), ptlen, key(0), keylen, iv(0), ivlen, ByVal 0&, 0, PKI_AEAD_AES_128_GCM) Debug.Print "CT=" & cnvHexStrFromBytes(ct) Debug.Print "OK=" & strOK ' Repeat but prepend IV to output ctlen = CIPHER_EncryptAEAD(ByVal 0&, 0, pt(0), ptlen, key(0), keylen, iv(0), ivlen, ByVal 0&, 0, PKI_AEAD_AES_128_GCM Or PKI_IV_PREFIX) Debug.Print "CIPHER_EncryptAEAD returns " & ctlen Debug.Assert ctlen > 0 ReDim ct(ctlen - 1) ctlen = CIPHER_EncryptAEAD(ct(0), ctlen, pt(0), ptlen, key(0), keylen, iv(0), ivlen, ByVal 0&, 0, PKI_AEAD_AES_128_GCM Or PKI_IV_PREFIX) Debug.Print "IV|CT=" & cnvHexStrFromBytes(ct)
This should result in output as follows:
KY=FEFFE9928665731C6D6A8F9467308308 IV=CAFEBABEFACEDBADDECAF888 PT=D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A721C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B391AAFD255 CIPHER_EncryptAEAD returns 80 CT=42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E091473F59854D5C2AF327CD64A62CF35ABD2BA6FAB4 OK=42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62cf35abd2ba6fab4 CIPHER_EncryptAEAD returns 92 IV|CT=CAFEBABEFACEDBADDECAF88842831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E091473F59854D5C2AF327CD64A62CF35ABD2BA6FAB4
Dim key() As Byte Dim iv() As Byte Dim pt() As Byte Dim ct() As Byte Dim lpDummy() As Byte ' GCM Test Case #03 (AES-128) key = cnvBytesFromHexStr("feffe9928665731c6d6a8f9467308308") iv = cnvBytesFromHexStr("cafebabefacedbaddecaf888") pt = cnvBytesFromHexStr("d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255") ct = cipherEncryptAEAD(pt, key, iv, lpDummy, PKI_AEAD_AES_128_GCM Or PKI_IV_PREFIX) Debug.Print "IV|CT=" & cnvHexStrFromBytes(ct) Debug.Print "OK= " & _ "CAFEBABEFACEDBADDECAF888" & _ "42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E091473F59854D5C2AF327CD64A62CF35ABD2BA6FAB4"
Encrypt data in a byte array using the specified block cipher algorithm, mode and padding. The key and initialization vector are passed as byte arrays.
Public Declare Function CIPHER_EncryptBytes Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpInput As Byte, ByVal nInputLen As Long, ByRef lpKey As Byte, ByVal nKeyLen As Long, ByRef lpIV As Byte, ByVal nIvLen As Long, ByVal strAlgModePad As String, ByVal nOptions As Long) As Long
nRet = CIPHER_EncryptBytes(lpOutput(0), nOutBytes, lpInput(0), nInputLen, lpKey(0), nKeylen, lpIV(0), nIvLen, strAlgModePad, nOptions)
long __stdcall CIPHER_EncryptBytes(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpInput, long nInputLen, const unsigned char *lpKey, long nKeyLen, const unsigned char *lpIV, long nIvLen, const char *szAlgModePad, long nOptions);
NULL for ECB mode.If successful, the return value is the number of bytes required in the output; otherwise it returns a negative error code.
Public Function cipherEncryptBytes (lpInput() As Byte, lpKey() As Byte, lpIV() As Byte, szAlgModePad As String, Optional nOptions As Long = 0) As Byte()
Cipher.Encrypt Method (Byte[], Byte[], Byte[], CipherAlgorithm, Mode, Padding, Cipher.Opts)
static bvec_t dipki::Cipher::Encrypt (const bvec_t &data, const bvec_t &key, const bvec_t &iv, Alg alg, Mode mode=Mode::ECB, Padding pad=Padding::Default, Opts opts=Opts::None)
static bvec_t dipki::Cipher::Encrypt (const bvec_t &data, const bvec_t &key, const bvec_t &iv, const std::string algModePad, Opts opts=Opts::None)
static Cipher.encrypt_block(data, key, iv=None, alg=Alg.TDEA, mode=Mode.ECB)
static Cipher.encrypt(data, key, iv=None, algmodepad='', alg=None, mode=Mode.ECB, pad=Pad.DEFAULT, opts=Opts.DEFAULT)
static Cipher.encrypt_block(data, key, iv=None, alg=Alg.TDEA, mode=Mode.ECB)
Padding is added as specified to the input before encryption. The user must allocate an output buffer of the required length, which will always be at least as long as the input, or longer if padding is to be added.
The algorithm/mode/padding must be specified using either the szAlgModePad string or nOptions parameter, but not both (see Specifying the algorithm, mode and padding for generic block cipher functions). The length of key lpKey must be exactly the required key size, and the length of the IV, if required, exactly the block size. See Valid key and block sizes.
If nOutBytes is set to zero or lpOutput set to 0 (or NULL in C or ByVal 0& in VBA),
the required number of bytes will be returned.
If the NoPadding option is specified, the required output length will be the same as the input.
Defaults: If padding is not specified then the default padding method depends on the cipher mode:
pkcs5padding will be used for ECB and CBC mode and nopadding for all other modes.
The default cipher mode is ECB.
Thus "aes128" is the same as "aes128/ecb/pkcs5padding".
Note that padding is only needed for ECB or CBC mode where the input length is not a multiple of the block size.
It is an error (BAD_LENGTH_ERROR) to specify NoPadding with ECB or CBC mode if the length of the input
is not an exact multiple of the block size.
The padding option is ignored for CTR, OFB and CFB modes, which do not need padding.
The default nopadding is always used for these modes regardless of what is specified
(so just use the default, e.g. "aes128/ctr").
[New in v12.3]
Use the PKI_IV_PREFIX to prepend the IV before the ciphertext in the output.
This will add the IV before the ciphertext in the form IV||CT.
This is the scheme used with block ciphers in XML encryption (see section 5.2 of [XMLENC])
where they use the phrase "The resulting cipher text is prefixed by the IV."
It is the responsibility of the receiver to parse this data to recover the IV.
Dim key() As Byte
Dim iv() As Byte
Dim pt() As Byte
Dim ct() As Byte
Dim ok() As Byte
Dim ptlen As Long
Dim ctlen As Long
Dim keylen As Long
Dim ivlen As Long
Dim algstr As String
algstr = "Aes128/CBC/OneAndZeroes"
Debug.Print algstr
key = cnvBytesFromHexStr("0123456789ABCDEFF0E1D2C3B4A59687")
iv = cnvBytesFromHexStr("FEDCBA9876543210FEDCBA9876543210")
keylen = UBound(key) + 1
ivlen = UBound(iv) + 1
Debug.Print "KY=" & cnvHexStrFromBytes(key)
Debug.Print "IV=" & cnvHexStrFromBytes(iv)
' "Now is the time for all good men to"
pt = cnvBytesFromHexStr("4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F")
ptlen = UBound(pt) + 1
' Correct result
ok = cnvBytesFromHexStr("C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B")
Debug.Print ("PT=" & cnvHexStrFromBytes(pt))
Debug.Print ("PT='" & StrConv(pt, vbUnicode) + "'")
' 1. Find out how long an output buffer we need
ctlen = CIPHER_EncryptBytes(0, 0, pt(0), ptlen, key(0), keylen, iv(0), ivlen, algstr, 0)
Debug.Print "CIPHER_EncryptBytes returns " & ctlen
' 2. Allocate the buffer
ReDim ct(ctlen - 1)
' 3. Encrypt to output buffer
ctlen = CIPHER_EncryptBytes(ct(0), ctlen, pt(0), ptlen, key(0), keylen, iv(0), ivlen, algstr, 0)
Debug.Print "CT=" & cnvHexStrFromBytes(ct)
Debug.Print "OK=" & cnvHexStrFromBytes(ok)
' PART 2 - prefix the IV in the output
ctlen = CIPHER_EncryptBytes(0, 0, pt(0), ptlen, key(0), keylen, iv(0), ivlen, algstr, PKI_IV_PREFIX)
Debug.Print "CIPHER_EncryptBytes(PKI_IV_PREFIX) returns " & ctlen
ReDim ct(ctlen - 1)
ctlen = CIPHER_EncryptBytes(ct(0), ctlen, pt(0), ptlen, key(0), keylen, iv(0), ivlen, algstr, PKI_IV_PREFIX)
Debug.Print "IV||CT=" & cnvHexStrFromBytes(ct)
This should result in output as follows:
Aes128/CBC/OneAndZeroes KY=0123456789ABCDEFF0E1D2C3B4A59687 IV=FEDCBA9876543210FEDCBA9876543210 PT=4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F PT='Now is the time for all good men to' CIPHER_EncryptBytes returns 48 CT=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B OK=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B
[New in v12.3] Use the PKI_IV_PREFIX option to prepend the IV to the ciphertext in the output.
CIPHER_EncryptBytes(PKI_IV_PREFIX) returns 64
IV||CT=FEDCBA9876543210FEDCBA9876543210C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B
<------IV (16 bytes)-----------><--------CT (48 bytes)------------------------------------------------------------------------->
For another example of using PKI_IV_PREFIX see the second example in CIPHER_DecryptBytes.
Dim key() As Byte Dim iv() As Byte Dim pt() As Byte Dim ct() As Byte Dim dt() As Byte Dim algstr As String ' PART 1 algstr = "Aes128/CBC/OneAndZeroes" Debug.Print algstr key = cnvBytesFromHexStr("0123456789ABCDEFF0E1D2C3B4A59687") iv = cnvBytesFromHexStr("FEDCBA9876543210FEDCBA9876543210") ' "Now is the time for all good men to" pt = cnvBytesFromHexStr("4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F") ct = cipherEncryptBytes(pt, key, iv, algstr, 0) Debug.Print "CT=" & cnvHexStrFromBytes(ct) Debug.Print "OK=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B" dt = cipherDecryptBytes(ct, key, iv, algstr, 0) Debug.Print "dt='" & StrConv(dt, vbUnicode) & "'" ' PART 2 - Use CTR mode and prefix the IV in the output algstr = "Aes128/CTR" Debug.Print algstr & " + PREFIX" ct = cipherEncryptBytes(pt, key, iv, algstr, PKI_IV_PREFIX) Debug.Print "CT=" & cnvHexStrFromBytes(ct) dt = cipherDecryptBytes(ct, key, iv, algstr, PKI_IV_PREFIX) Debug.Print "dt='" & StrConv(dt, vbUnicode) & "'" ' PART 3 - Use ECB mode and note we use a dummy empty byte array for the IV Dim dummy() As Byte algstr = "Aes128/ECB" Debug.Print algstr ct = cipherEncryptBytes(pt, key, dummy, algstr, 0) Debug.Print "CT=" & cnvHexStrFromBytes(ct) dt = cipherDecryptBytes(ct, key, dummy, algstr, 0) Debug.Print "dt='" & StrConv(dt, vbUnicode) & "'"
@deprecated use CIPHER_EncryptBytes.
Encrypt data using the specified block cipher algorithm, mode and padding. The input data, key and initialization vector are all represented as hexadecimal strings.
Public Declare Function CIPHER_EncryptHex Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strInputHex As String, ByVal strKeyHex As String, ByVal strIvHex As String, ByVal strAlgModePad As String, ByVal nOptions As Long) As Long
nRet = CIPHER_EncryptHex(strOutput, nOutChars, strInputHex, strKeyHex, strIvHex, strAlgModePad, nOptions)
long __stdcall CIPHER_EncryptHex(char *szOutput, long nOutChars, const char *szInputHex, const char *szKeyHex, const char *szIvHex, const char *szAlgModePad, long nOptions);
"").If successful, the return value is the number of characters in or required in the output; otherwise it returns a nonzero error code.
Public Function cipherEncryptHex (szInputHex As String, szKeyHex As String, szIvHex As String, szAlgModePad As String, Optional nOptions As Long = 0) As String
Cipher.Encrypt Method (String, String, String, CipherAlgorithm, Mode, Padding, Cipher.Opts)
static Cipher.encrypt_hex(datahex, keyhex, ivhex='', algmodepad='', alg=None, mode=Mode.ECB, pad=Pad.DEFAULT, opts=Opts.DEFAULT)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
This is the equivalent of CIPHER_EncryptBytes with all parameters passed as hex-encoded strings instead of byte arrays.
It is similar to the CIPHER_Hex function except this accepts variable-length input and adds padding if required, as well as the option to prepend the IV to the ciphertext.
Padding is added as specified to the input before encryption. The output will always be at least as long as the input, or longer if padding or a prefixed IV is to be added.
The algorithm/mode/padding must be specified using either the szAlgModePad string or nOptions parameter, but not both (see Specifying the algorithm, mode and padding for generic block cipher functions).
It is an error (BAD_PARAM_ERROR) to pass the empty string "" as input in szInputHex.
The output buffer strOutput should not be the same as the input strInputHex.
Use the PKI_IV_PREFIX option to prepend the IV before the ciphertext in the output.
This will add the IV before the ciphertext in the form IV||CT.
This is the scheme used with block ciphers in XML encryption (see section 5.2 of [XMLENC])
where they use the phrase "The resulting cipher text is prefixed by the IV."
Dim strKey As String Dim strIV As String Dim strPlain As String Dim strCipher As String Dim strOK As String Dim strAlg As String Dim nChars As Long strAlg = "Aes128/CBC/OneAndZeroes" Debug.Print strAlg strKey = "0123456789ABCDEFF0E1D2C3B4A59687" strIV = "FEDCBA9876543210FEDCBA9876543210" Debug.Print "KY=" & strKey Debug.Print "IV=" & strIV ' "Now is the time for all good men to" strPlain = "4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F" Debug.Print "PT=" & strPlain Debug.Print "PT='" & cnvStringFromHexStr(strPlain) & "'" ' Correct result strOK = "C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B" ' 1. Find out how long an output buffer we need nChars = CIPHER_EncryptHex(vbNullString, 0, strPlain, strKey, strIV, strAlg, 0) Debug.Print "CIPHER_EncryptHex returns " & nChars Debug.Assert nChars > 0 ' 2. Allocate the buffer strCipher = String(nChars, " ") ' 3. Encrypt to output buffer nChars = CIPHER_EncryptHex(strCipher, nChars, strPlain, strKey, strIV, strAlg, 0) Debug.Print "CT=" & strCipher Debug.Print "OK=" & strOK ' PART 2 - prefix the IV in the output nChars = CIPHER_EncryptHex(vbNullString, 0, strPlain, strKey, strIV, strAlg, PKI_IV_PREFIX) Debug.Print "CIPHER_EncryptHex(PKI_IV_PREFIX) returns " & nChars Debug.Assert nChars > 0 strCipher = String(nChars, " ") nChars = CIPHER_EncryptHex(strCipher, nChars, strPlain, strKey, strIV, strAlg, PKI_IV_PREFIX) Debug.Print "IV||CT=" & strCipher
This should result in output as follows:
Aes128/CBC/OneAndZeroes KY=0123456789ABCDEFF0E1D2C3B4A59687 IV=FEDCBA9876543210FEDCBA9876543210 PT=4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F PT='Now is the time for all good men to' CIPHER_EncryptHex returns 96 CT=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B OK=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B CIPHER_EncryptHex(PKI_IV_PREFIX) returns 128 IV||CT=FEDCBA9876543210FEDCBA9876543210C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E1771D4CDA34FBFB7E74B321F9A2CF4EA61B
Dim strKeyHex As String Dim strIvHex As String Dim strPlainHex As String Dim strCipherHex As String strKeyHex = "0123456789ABCDEFF0E1D2C3B4A59687" strIvHex = "FEDCBA9876543210FEDCBA9876543210" strPlainHex = "4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F" ' Get encrypted output directly in hex strCipherHex = cipherEncryptHex(strPlainHex, strKeyHex, strIvHex, "Aes128/CBC/OneAndZeroes", 0) Debug.Print strCipherHex ' Same again with bytes Dim lpKey() As Byte Dim lpIV() As Byte Dim lpPlain() As Byte Dim lpCipher() As Byte lpPlain = StrConv("Now is the time for all good men to", vbFromUnicode) lpKey = cnvBytesFromHexStr("0123456789ABCDEFF0E1D2C3B4A59687") lpIV = cnvBytesFromHexStr("FEDCBA9876543210FEDCBA9876543210") ' Get encrypted output lpCipher = cipherEncryptBytes(lpPlain, lpKey, lpIV, "Aes128/CBC/OneAndZeroes", 0) Debug.Print cnvHexStrFromBytes(lpCipher) ' Same again using ECB mode with default PKCS#5 padding ' To pass an empty byte array for IV, create a dummy zero-length array Dim lpDummy() As Byte lpCipher = cipherEncryptBytes(lpPlain, lpKey, lpDummy, "Aes128/ECB", 0) Debug.Print cnvHexStrFromBytes(lpCipher) ' The old way - we need all the byte array lengths Dim nBytes As Long Dim nDataLen As Long Dim nKeyLen As Long Dim nIVLen As Long nDataLen = cnvBytesLen(lpPlain) nKeyLen = cnvBytesLen(lpKey) nIVLen = cnvBytesLen(lpIV) nBytes = CIPHER_EncryptBytes(ByVal 0&, 0, lpPlain(0), nDataLen, lpKey(0), nKeyLen, lpIV(0), nIVLen, "Aes128/CBC/OneAndZeroes", 0) Debug.Assert nBytes > 0 ReDim lpCipher(nBytes - 1) nBytes = CIPHER_EncryptBytes(lpCipher(0), nBytes, lpPlain(0), nDataLen, lpKey(0), nKeyLen, lpIV(0), nIVLen, "Aes128/CBC/OneAndZeroes", 0) Debug.Print cnvHexStrFromBytes(lpCipher) ' Same again with hex using ECB mode with default PKCS#5 padding ' To pass a "null" IV in hex, just use the empty string strCipherHex = cipherEncryptHex(strPlainHex, strKeyHex, "", "Aes128/ECB", 0) Debug.Print strCipherHex ' Or vbNullString strCipherHex = cipherEncryptHex(strPlainHex, strKeyHex, vbNullString, "Aes128/ECB", 0) Debug.Print strCipherHex
Encrypt or decrypt data in a file using the specified block cipher algorithm and mode.
@deprecated
Use CIPHER_FileEncrypt() or CIPHER_FileDecrypt() instead.
Public Declare Function CIPHER_File Lib "diCrPKI.dll"
(ByVal fEncrypt As Long, ByVal strFileOut As String, ByVal strFileIn As String,
ByRef lpKey As Byte, ByRef lpIV As Byte, ByVal strAlgAndMode As String, ByVal nOptions As Long) As Long
nRet = CIPHER_File(fEncrypt, strFileOut, strFileIn, lpKey(0),
lpIV(0), strAlgAndMode, nOptions)
long __stdcall CIPHER_File(long fEncrypt, const char *szFileOut, const char *szFileIn, const unsigned char *lpKey, const unsigned char *lpIV, const char *szAlgAndMode, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Cipher.FileEncrypt Method
Cipher.FileDecrypt Method
The key and initialization vector are passed as bytes arrays. PKCS5 padding is used, if required. The algorithm and mode must be specified using either the szAlgAndMode or nOptions parameter (see Specifying the algorithm and mode for generic block cipher functions). The length of key lpKey must be exactly the required key size, and the length of the IV, if required, exactly the block size. See Valid key and block sizes. The output file szFileOut will be overwritten without warning. If there is an error, the output file will not exist. The input and output files must not be the same. In ECB and CBC modes, a padding string will be added or assumed according to the method outlined in Section 6.3 of [CMS], which is the same as the padding method in [PKCS7] section 10.3 and [PKCS5] section 6.1.1 and [RFC1423] para 1.1.
Const MY_PATH As String = "" Dim abKey() As Byte Dim abIV() As Byte Dim strFileEnc As String Dim strFileIn As String Dim strFileChk As String Dim nRet As Long ' Construct full path names to files strFileIn = MY_PATH & "hello.txt" strFileEnc = MY_PATH & "hello.aes128.enc.dat" strFileChk = MY_PATH & "hello.aes128.chk.txt" ' Create the key as an array of bytes ' This creates an array of 16 bytes {&HFE, &HDC, ... &H10} abKey = cnvBytesFromHexStr("fedcba9876543210fedcba9876543210") ' Create the IV at random ReDim abIV(PKI_BLK_AES_BYTES - 1) Call RNG_Bytes(abIV(0), PKI_BLK_AES_BYTES, "", 0) ' Display the IV (this needs to be communicated separately to the recipient) Debug.Print "IV=" & cnvHexStrFromBytes(abIV) ' Encrypt plaintext file to ciphertext using AES-128 in counter (CTR) mode ' (This will create a file of exactly the same size as the input) nRet = CIPHER_File(ENCRYPT, strFileEnc, strFileIn, abKey(0), abIV(0), "aes128-ctr", 0) Debug.Print "CIPHER_File(ENCRYPT) returns " & nRet ' Now decrypt it nRet = CIPHER_File(DECRYPT, strFileChk, strFileEnc, abKey(0), abIV(0), "aes128-ctr", 0) Debug.Print "CIPHER_File(DECRYPT) returns " & nRet
Decrypt a file using specified block cipher algorithm, mode and padding.
Public Declare Function CIPHER_FileDecrypt Lib "diCrPKI.dll"
(ByVal strFileOut As String, ByVal strFileIn As String,
ByRef lpKey As Byte, ByVal nKeyLen As Long, ByRef lpIV As Byte, ByVal nKeyLen As Long,
ByVal strAlgModePad As String, ByVal nOptions As Long) As Long
nRet = CIPHER_FileDecrypt(strFileOut, strFileIn, lpKey(0), nKeyLen, lpIV(0), nIvLen, strAlgModePad, nOptions)
long __stdcall CIPHER_FileDecrypt(const char *szFileOut, const char *szFileIn, const unsigned char *lpKey, long nKeyLen, const unsigned char *lpIV, long nIvLen, const char *szAlgModePad, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function cipherFileDecrypt (szFileOut As String, szFileIn As String, lpKey() As Byte, lpIV() As Byte, szAlgModePad As String, Optional nOptions As Long = 0) As Long
Cipher.FileDecrypt Method (String, String, Byte[], Byte[], CipherAlgorithm, Mode, Padding, Cipher.Opts)
Cipher.FileDecrypt Method (String, String, String, String, CipherAlgorithm, Mode, Padding, Cipher.Opts)
static int dipki::Cipher::FileDecrypt (const std::string &fileOut, const std::string &fileIn, const bvec_t &key, const bvec_t &iv, Alg alg, Mode mode=Mode::ECB, Padding pad=Padding::Default, Opts opts=Opts::None)
static Cipher.file_decrypt(fileout, filein, key, iv, algmodepad='', alg=None, mode=Mode.ECB, pad=Pad.DEFAULT, opts=Opts.DEFAULT)
The algorithm/mode/padding must be specified using either the szAlgModePad string or nOptions parameter, but not both (see Specifying the algorithm, mode and padding for generic block cipher functions). The length of key must be exactly the required key size, and the length of the IV, if required, exactly the block size. See Valid key and block sizes. The output file szFileOut will be overwritten without warning. If there is an error, the output file will not exist. The input and output files must not be the same.
Prepended IV: If the ciphertext file was created with the IV prepended at the start of the file, then you
must specify the PKI_IV_PREFIX option. In this case, the lpIV parameter is ignored and should be set to NULL.
The input file is expected to be of the form IV||ciphertext, or
IV||ciphertext||tag for AES-GCM.
Defaults: If padding is not specified then the default padding method depends on the cipher mode:
pkcs5padding will be used for ECB and CBC mode and nopadding for all other modes.
The default cipher mode is ECB.
Thus "aes128" is the same as "aes128/ecb/pkcs5padding".
Padding: When decrypting you can specify NoPadding to leave any padding intact in the deciphered file.
This is useful if you wish to examine an unknown padding scheme.
Otherwise, when decrypting in ECB or CBC mode, you must specify the same padding scheme used when encrypting.
It is an error (DECRYPT_ERROR) if the expected padding string is not found after decrypting.
The padding parameter is ignored when decrypting in CTR, OFB or CFB mode.
GCM mode: [New in v20.7] Use aes*-gcm to decrypt the file using AES-GCM mode. A 16-byte tag (mac) must be appended at the end of the file. Only a 16-byte tag is supported. The IV must be exactly 12 bytes long for AES-GCM mode. Use the PKI_IV_PREFIX flag to indicate that the IV is at the start of the file.
See example in CIPHER_FileEncrypt.
Encrypt a file using specified block cipher algorithm, mode and padding. The IV may be prepended to the file, if required.
Public Declare Function CIPHER_FileEncrypt Lib "diCrPKI.dll"
(ByVal strFileOut As String, ByVal strFileIn As String,
ByRef lpKey As Byte, ByVal nKeyLen As Long, ByRef lpIV As Byte, ByVal nKeyLen As Long,
ByVal strAlgModePad As String, ByVal nOptions As Long) As Long
nRet = CIPHER_FileEncrypt(strFileOut, strFileIn, lpKey(0), nKeyLen,
lpIV(0), nIvLen, strAlgModePad, nOptions)
long __stdcall CIPHER_FileEncrypt(const char *szFileOut, const char *szFileIn, const unsigned char *lpKey, long nKeyLen, const unsigned char *lpIV, long nIvLen, const char *szAlgModePad, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function cipherFileEncrypt (szFileOut As String, szFileIn As String, lpKey() As Byte, lpIV() As Byte, szAlgModePad As String, Optional nOptions As Long = 0) As Long
Cipher.FileEncrypt Method (String, String, Byte[], Byte[], CipherAlgorithm, Mode, Padding, Cipher.Opts)
Cipher.FileEncrypt Method (String, String, String, String, CipherAlgorithm, Mode, Padding, Cipher.Opts)
static int dipki::Cipher::FileEncrypt (const std::string &fileOut, const std::string &fileIn, const bvec_t &key, const bvec_t &iv, Alg alg, Mode mode=Mode::ECB, Padding pad=Padding::Default, Opts opts=Opts::None)
static Cipher.file_encrypt(fileout, filein, key, iv, algmodepad='', alg=None, mode=Mode.ECB, pad=Pad.DEFAULT, opts=Opts.DEFAULT)
The algorithm/mode/padding must be specified using either the szAlgModePad string or nOptions parameter, but not both (see Specifying the algorithm, mode and padding for generic block cipher functions). The length of key must be exactly the required key size, and the length of the IV, if required, exactly the block size. See Valid key and block sizes. The output file szFileOut will be overwritten without warning. If there is an error, the output file will not exist. The input and output files must not be the same.
Prepended IV: If the PKI_IV_PREFIX option flag is set in nOptions then the IV will be
prepended (i.e. added) at the start of the output file.
That is, the output file will be of the form IV||ciphertext.
The PKI_IV_PREFIX flag is ignored in ECB mode where an IV is not needed.
Defaults: If padding is not specified then the default padding method depends on the cipher mode:
pkcs5padding will be used for ECB and CBC mode and nopadding for all other modes.
The default cipher mode is ECB.
Thus "aes128" is the same as "aes128/ecb/pkcs5padding".
Padding: In normal circumstances you should leave the padding unspecified and use the default padding when encrypting.
The only time it should be required is if you want to use an exotic padding like OneAndZeroesPadding
instead of pkcs5padding with EBC or CBC mode.
Note that, unlike the behaviour with CIPHER_EncryptBytes,
it is an error (BAD_PARAM_ERROR) to specify NoPadding when encrypting a file with ECB or CBC mode
under any circumstances.
The padding option is ignored for CTR, OFB and CFB modes; that is,
the default nopadding is always used for these modes regardless of what is specified (so just use the default,
e.g. "aes128/ctr").
GCM mode: [New in v21.0] Use aes128-gcm, aes192-gcm or aes256-gcm to encrypt the file using AES-GCM mode. A 16-byte tag (mac) is always appended to the file. The IV must be exactly 12 bytes long for AES-GCM mode. Add the PKI_IV_PREFIX flag to prepend the IV at the start of the output file (this is in accordance with section 5.2.4 of [XMLENC]).
Dim abKey() As Byte Dim abIV() As Byte Dim nKeyLen As Long Dim nIvLen As Long Dim strFileEnc As String Dim strFileIn As String Dim strFileChk As String Dim strAlgModePad As String Dim nRet As Long ' Construct full path names to files strFileIn = "hello.txt" strFileEnc = "hello.aes192.enc.dat" strFileChk = "hello.aes192.chk.txt" ' Check input file Debug.Print "FileLen('" & strFileIn & "')=" & FileLen(strFileIn) ' Create the AES-192 key as an array of 24 bytes abKey = cnvBytesFromHexStr("fedcba9876543210fedcba98765432101122334455667788") nKeyLen = UBound(abKey) + 1 Debug.Print "KY=" & cnvHexStrFromBytes(abKey) Debug.Print "LEN(KY)=" & nKeyLen ' Create the IV at random ReDim abIV(PKI_BLK_AES_BYTES - 1) Call RNG_Bytes(abIV(0), PKI_BLK_AES_BYTES, "", 0) ' Display the IV (this will be prepended to the ciphertext in the output file) Debug.Print "IV=" & cnvHexStrFromBytes(abIV) nIvLen = UBound(abIV) + 1 Debug.Print "LEN(IV)=" & nIvLen ' Specify cipher alg/mode/padding strAlgModePad = "aes192/CBC/ANSIX923" Debug.Print strAlgModePad ' Encrypt the plaintext file, prefixing the IV nRet = CIPHER_FileEncrypt(strFileEnc, strFileIn, abKey(0), nKeyLen, abIV(0), nIvLen, strAlgModePad, PKI_IV_PREFIX) Debug.Print "CIPHER_FileEncrypt() returns " & nRet & " (expected 0)" Debug.Assert (0 = nRet) ' Check output file Debug.Print "FileLen('" & strFileEnc & "')=" & FileLen(strFileEnc) ' Now decipher using the IV already prefixed to the ciphertext nRet = CIPHER_FileDecrypt(strFileChk, strFileEnc, abKey(0), nKeyLen, 0, 0, strAlgModePad, PKI_IV_PREFIX) Debug.Print "CIPHER_FileDecrypt() returns " & nRet & " (expected 0)" Debug.Assert (0 = nRet) ' Check decrypted file - it should match the original plaintext Debug.Print "FileLen('" & strFileChk & "')=" & FileLen(strFileChk) Debug.Assert (FileLen(strFileChk) = FileLen(strFileIn))
The input file is 13 bytes long ("hello world\r\n"). This is padded to 16 bytes when encrypted in CBC mode.
The output file contains 16 bytes of ciphertext plus the prepended IV of 16 bytes,
so it is 32 bytes long.
FileLen('hello.txt')=13
KY=FEDCBA9876543210FEDCBA98765432101122334455667788
LEN(KY)=24
IV=ECD982FF61DDC6506828690D20B55BBE
LEN(IV)=16
aes192/CBC/ANSIX923
CIPHER_FileEncrypt() returns 0 (expected 0)
FileLen('hello.aes192.enc.dat')=32
CIPHER_FileDecrypt() returns 0 (expected 0)
FileLen('hello.aes192.chk.txt')=13
Encrypt or decrypt data represented as a hexadecimal string. The key and initialization vector are represented as a hexadecimal string.
Public Declare Function CIPHER_Hex Lib "diCrPKI.dll"
(ByVal fEncrypt As Long, ByVal strOutput As String, ByVal nOutChars As Long, ByVal strData As String,
ByVal strKey As String, ByVal strIV As String, ByVal strAlgAndMode As String, ByVal nOptions As Long) As Long
nRet = CIPHER_Hex(fEncrypt, strOutput, nOutChars, strInput, strKey, strIV, strAlgAndMode, nOptions)
long __stdcall CIPHER_Hex(long fEncrypt, char *szOutput, long nOutChars, const char *szData, const char *szKey, const char *szIV, const char *szAlgAndMode, long nOptions);
"" for ECB mode.If successful, the return value is zero; otherwise it returns a nonzero error code.
Cipher.Encrypt Method (String, String, String, CipherAlgorithm, Mode)
Cipher.Decrypt Method (String, String, String, CipherAlgorithm, Mode)
The algorithm and mode must be specified using either the szAlgAndMode or nOptions parameter (see Specifying the algorithm and mode for generic block cipher functions). All data parameters are expected to be in hexadecimal-encoded format and to be of valid lengths. Valid hexadecimal characters are [0-9A-Fa-f]. The hex-encoded key string szKey must represent a value with a length of exactly the required key size. The hex-encoded initialization vector string szIV, if required, must represent a value with a length of exactly the block size. See Valid key and block sizes. Important: The output string szOutput must be dimensioned with at least the same number of characters as the input string before calling. The variables szOutput and szInput should be different.
For ECB and CBC modes, the length of the input string szInput must be an exact multiple of
the block size encoded in hex characters
otherwise a BAD_LENGTH_ERROR error will occur.
It is the responsibility of the user to provide suitable padding before encrypting in those modes
and to remove any padding after decrypting.
[New in v20.0] Consider using the newer functions CIPHER_EncryptHex and CIPHER_DecryptHex. These functions take a variable length input and add (or remove) the required padding, and provide the option to prepend the IV to the ciphertext.
This example is from Section 8.1 of [SMIME-EX].
Dim nRet As Long Dim sPlain As String Dim sCipher As String Dim sCheck As String Dim sKey As String Dim sInitV As String Dim sCorrect As String sPlain = "5468697320736F6D652073616D706520636F6E74656E742E0808080808080808" ' T h i s _ s o m e _ s a m p e _ c o n t e n t .(+padding 8 x 08) sKey = "737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32" sInitV = "B36B6BFB6231084E" sCorrect = "d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4" ' Set output to be same length as input sCipher = String(Len(sPlain), " ") Debug.Print "KY=" & sKey Debug.Print "PT=" & sPlain ' Encrypt using strAlgAndMode nRet = CIPHER_Hex(ENCRYPT, sCipher, Len(sCipher), sPlain, sKey, sInitV, "tdea-cbc", 0) Debug.Print "CT=" & sCipher & nRet Debug.Print "OK=" & sCorrect ' Alternative using nOptions nRet = CIPHER_Hex(ENCRYPT, sCipher, Len(sCipher), sPlain, sKey, sInitV, "", PKI_BC_TDEA + PKI_MODE_CBC) Debug.Print "CT=" & sCipher & nRet Debug.Print "OK=" & sCorrect ' Decrypt using strAlgAndMode sCheck = String(Len(sCipher), " ") nRet = CIPHER_Hex(DECRYPT, sCheck, Len(sCheck), sCipher, sKey, sInitV, "tdea-cbc", 0) Debug.Print "P'=" & sCheck & nRet ' Alternative using nOptions sCheck = String(Len(sCipher), " ") nRet = CIPHER_Hex(DECRYPT, sCheck, Len(sCheck), sCipher, sKey, sInitV, "", PKI_BC_TDEA + PKI_MODE_CBC) Debug.Print "P'=" & sCheck & nRet
This should result in output as follows:
KY=737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32 PT=5468697320736F6D652073616D706520636F6E74656E742E0808080808080808 CT=D76FD1178FBD02F84231F5C1D2A2F74A4159482964F675248254223DAF9AF8E4 0 OK=d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4 CT=D76FD1178FBD02F84231F5C1D2A2F74A4159482964F675248254223DAF9AF8E4 0 OK=d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4 P'=5468697320736F6D652073616D706520636F6E74656E742E0808080808080808 0 P'=5468697320736F6D652073616D706520636F6E74656E742E0808080808080808 0
CIPHER_Bytes CIPHER_File CIPHER_EncryptHex CIPHER_DecryptHex
Wrap a content-encryption key with a key-encryption key.
Public Declare Function CIPHER_KeyWrap Lib "diCrPKI.dll"
(ByRef lpOutput As Byte, ByVal nOutBytes As Long,
ByRef lpData As Byte, ByVal nDataLen As Long,
ByRef lpKek As Byte, ByVal nKekLen As Long, ByVal nOptions As Long) As Long
nRet = CIPHER_KeyWrap(lpOutput(0), nOutBytes, lpData(0), nDataLen,
lpKek(0), nKekLen, nOptions)
long __stdcall CIPHER_KeyWrap(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpData, long nDataLen, const unsigned char *lpKek, long nKekLen, long nOptions);
AES128-WrapAES128-WrapAES128-Wrapcms3DESWrapIf successful, the return value is the number of bytes in the output; otherwise it returns a negative error code.
Public Function cipherKeyWrap (lpData() As Byte, lpKEK() As Byte, nOptions As Long) As Byte()
static bvec_t dipki::Cipher::KeyWrap (const bvec_t &data, const bvec_t &kek, Alg alg)
static Cipher.key_wrap(data, kek, alg)
This wraps (encrypts) key material using a key encryption key (KEK) and uses either the AES Key Wrap Algorithm from [RFC3394] or the Triple-DES Key Wrap algorithm from [RFC3217]. There is no default algorithm. The algorithm must be specified in the nOptions parameter. The input data to be wrapped must be a valid length for the underlying data encapsulation mechanism; specifically, at least 16 bytes and a multiple of 8 bytes for AES, or exactly 24 bytes for Triple DES. To find the required length for the output wrapped key, pass zero as the nOutBytes parameter (Hint: an AES-wrapped key is exactly 8 bytes longer than the input; a triple-DES-wrapped key is 16 bytes longer). No parity bit checks or changes are made for a Triple-DES key.
Changed in [v20.5]: Added the explicit key wrap options PKI_KWRAP_* which are different from the old PKI_BC_* options. The old PKI_BC_* options are still accepted for backwards compatibility.
Dim abWK() As Byte
Dim abKeyData() As Byte
Dim abKek() As Byte
Dim nWkLen As Long
Dim nKdLen As Long
Dim nKekLen As Long
abKeyData = cnvBytesFromHexStr("00112233 44556677 8899aabb ccddeeff")
abKek = cnvBytesFromHexStr("c17a44e8 e28d7d64 81d1ddd5 0a3b8914")
nKdLen = UBound(abKeyData) + 1
nKekLen = UBound(abKek) + 1
nWkLen = CIPHER_KeyWrap(0, 0, abKeyData(0), nKdLen, abKek(0), nKekLen, PKI_BC_AES128)
If nWkLen <= 0 Then
Debug.Print " returns " & nWkLen & ": " & pkiErrorLookup(nWkLen)
Exit Sub
End If
ReDim abWK(nWkLen - 1)
nWkLen = CIPHER_KeyWrap(abWK(0), nWkLen, abKeyData(0), nKdLen, abKek(0), nKekLen, PKI_BC_AES128)
Debug.Print "WK=" & cnvHexStrFromBytes(abWK)
abKeyData = cnvBytesFromHexStr("8cbedec4 8d063e1b a46be8e3 69a9c398 d8e30ee5 42bc347c 4f30e928 ddd7db49")
abKek = cnvBytesFromHexStr("9e84ee99 e6a84b50 c76cd414 a2d2ec05 8af41bfe 4bf3715b f894c8da 1cd445f6")
nKdLen = UBound(abKeyData) + 1
nKekLen = UBound(abKek) + 1
nWkLen = CIPHER_KeyWrap(0, 0, abKeyData(0), nKdLen, abKek(0), nKekLen, PKI_BC_AES256)
If nWkLen <= 0 Then
Debug.Print " returns " & nWkLen & ": " & pkiErrorLookup(nWkLen)
Exit Sub
End If
ReDim abWK(nWkLen - 1)
nWkLen = CIPHER_KeyWrap(abWK(0), nWkLen, abKeyData(0), nKdLen, abKek(0), nKekLen, PKI_BC_AES256)
Debug.Print "WK=" & cnvHexStrFromBytes(abWK)
abKeyData = cnvBytesFromHexStr("84e7f2d8 78f89fcc cd2d5eba fc56daf7 3300f27e f771cd68")
abKek = cnvBytesFromHexStr("8ad8274e 56f46773 8edd83d4 394e5e29 af7c4089 e4f8d9f4")
nKdLen = UBound(abKeyData) + 1
nKekLen = UBound(abKek) + 1
nWkLen = CIPHER_KeyWrap(0, 0, abKeyData(0), nKdLen, abKek(0), nKekLen, PKI_BC_3DES)
If nWkLen <= 0 Then
Debug.Print " returns " & nWkLen & ": " & pkiErrorLookup(nWkLen)
Exit Sub
End If
ReDim abWK(nWkLen - 1)
nWkLen = CIPHER_KeyWrap(abWK(0), nWkLen, abKeyData(0), nKdLen, abKek(0), nKekLen, PKI_BC_3DES)
Debug.Print "WK=" & cnvHexStrFromBytes(abWK)
This should result in output as follows:
WK=503D75C73630A7B02ECF51B9B29B907749310B77B0B2E054 WK=EAFB901F82B98D37F17497063DE3E5EC7246AB57200AE73EDDDDF24AA403DAFA0C5AE151D1746FA4 WK=E6517B14A383D48AD71D2D80C98894A10C59901D69ABDF77E27A11B50370FAA21AF5231552D2C1F0
The AES key wrap will always give the same result for the same input data, but the triple DES result will be different each time.
Dim lpWK() As Byte
Dim lpKeyData() As Byte
Dim lpKek() As Byte
lpKeyData = cnvBytesFromHexStr("00112233 44556677 8899aabb ccddeeff")
lpKek = cnvBytesFromHexStr("c17a44e8 e28d7d64 81d1ddd5 0a3b8914")
' NB Specific nonzero option required in nOptions
lpWK = cipherKeyWrap(lpKeyData, lpKek, PKI_BC_AES128)
Debug.Print "WK=" & cnvHexStrFromBytes(lpWK)
Debug.Print "OK=503D75C73630A7B02ECF51B9B29B907749310B77B0B2E054"
' Now unwrap the KEK
Dim lpKeyUnwrapped() As Byte
lpKeyUnwrapped = cipherKeyUnwrap(lpWK, lpKek, PKI_BC_AES128)
Debug.Print "KY=" & cnvHexStrFromBytes(lpKeyUnwrapped)
Debug.Print "OK=00112233445566778899AABBCCDDEEFF"
Unwrap (decrypt) a content-encryption key with a key-encryption key.
Public Declare Function CIPHER_KeyUnwrap Lib "diCrPKI.dll"
(ByRef lpOutput As Byte, ByVal nOutBytes As Long,
ByRef lpData As Byte, ByVal nDataLen As Long,
ByRef lpKek As Byte, ByVal nKekLen As Long, ByVal nOptions As Long) As Long
nRet = CIPHER_KeyUnwrap(lpOutput(0), nOutBytes, lpData(0), nDataLen, lpKek(0), nKekLen, nOptions)
long __stdcall CIPHER_KeyUnwrap(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpData, long nDataLen, const unsigned char *lpKek, long nKekLen, long nOptions);
AES128-WrapAES128-WrapAES128-Wrapcms3DESWrapIf successful, the return value is the number of bytes in the output; otherwise it returns a negative error code.
Public Function cipherKeyUnwrap (lpData() As Byte, lpKEK() As Byte, nOptions As Long) As Byte()
static bvec_t dipki::Cipher::KeyUnwrap (const bvec_t &data, const bvec_t &kek, Alg alg)
static Cipher.key_unwrap(data, kek, alg)
This unwraps (decrypts) key material using a key encryption key (KEK) and uses either the AES Key Wrap Algorithm from [RFC3394] or the Triple-DES Key Wrap algorithm from [RFC3217]. There is no default algorithm. The algorithm must be specified in the nOptions parameter. To find the required length for the output key material, pass zero as the nOutBytes parameter. This will be 8 bytes less than the input length for AES and 16 bytes less for triple DES. No parity bit checks or changes are made for a Triple-DES key.
Dim abWK() As Byte
Dim abKeyData() As Byte
Dim abKek() As Byte
Dim nWkLen As Long
Dim nKdLen As Long
Dim nKekLen As Long
abWK = cnvBytesFromHexStr("503D75C73630A7B02ECF51B9B29B907749310B77B0B2E054")
abKek = cnvBytesFromHexStr("c17a44e8 e28d7d64 81d1ddd5 0a3b8914")
nWkLen = UBound(abWK) + 1
nKekLen = UBound(abKek) + 1
nKdLen = CIPHER_KeyUnwrap(0, 0, abWK(0), nWkLen, abKek(0), nKekLen, PKI_BC_AES128)
If nKdLen <= 0 Then
Debug.Print " returns " & nKdLen & ": " & pkiErrorLookup(nKdLen)
Exit Sub
End If
ReDim abKeyData(nKdLen - 1)
nWkLen = CIPHER_KeyUnwrap(abKeyData(0), nKdLen, abWK(0), nWkLen, abKek(0), nKekLen, PKI_BC_AES128)
Debug.Print "K=" & cnvHexStrFromBytes(abKeyData)
This should result in output as follows:
K=00112233445566778899AABBCCDDEEFF
Dim lpWK() As Byte
Dim lpKeyData() As Byte
Dim lpKek() As Byte
lpKeyData = cnvBytesFromHexStr("00112233 44556677 8899aabb ccddeeff")
lpKek = cnvBytesFromHexStr("c17a44e8 e28d7d64 81d1ddd5 0a3b8914")
' NB Specific nonzero option required in nOptions
lpWK = cipherKeyWrap(lpKeyData, lpKek, PKI_BC_AES128)
Debug.Print "WK=" & cnvHexStrFromBytes(lpWK)
Debug.Print "OK=503D75C73630A7B02ECF51B9B29B907749310B77B0B2E054"
' Now unwrap the KEK
Dim lpKeyUnwrapped() As Byte
lpKeyUnwrapped = cipherKeyUnwrap(lpWK, lpKek, PKI_BC_AES128)
Debug.Print "KY=" & cnvHexStrFromBytes(lpKeyUnwrapped)
Debug.Print "OK=00112233445566778899AABBCCDDEEFF"
Extracts the message digest from a signed-data CMS object file and verifies the signature.
Public Declare Function CMS_GetSigDataDigest Lib "diCrPKI.dll"
(ByVal strHexDigest As String, ByVal nHexDigestLen As Long,
ByVal strFileIn As String, ByVal strCertFile As String,
ByVal nOptions As Long) As Long
nRet = CMS_GetSigDataDigest(strHexDigest, nHexDigestLen, strFileIn,
strCertFile, nOptions) As Long
long __stdcall CMS_GetSigDataDigest(char *szOutput, long nOutChars, const char *szFileIn, const char *szCertFile, long nOptions);
If successful, the return value is a non-negative value indicating the message digest algorithm (CAUTION: this is not the number of characters in the output); otherwise it returns a negative error code.
Public Function cmsGetSigDataDigest (szFileIn As String, Optional szCertFile As String = "", Optional nOptions As Long = 0) As String
static std::string dipki::Cms::GetSigDataDigest (const std::string &inputFile, const std::string &certFile="")
This function extracts the message digest of the signed encapsulated content.
In doing so, it also verifies that the signature is valid.
The object may be a "detached signature" object.
If signed attributes are present, the function will extract the messageDigest
attribute for RSA and DSA signature algorithms.
If signed attributes are not present, the message digest is extracted
directly from the signature value, but only for RSASSA-PKCS1-v1_5 signatures,
as the message digest cannot be directly extracted from a DSA or RSA-PSS signature.
If given, the function will use the public key from the specified X.509 certificate to validate the signature;
otherwise it will use the first valid SignerInfo and certificate pair it finds in the SignedData.
The message digest, if found, is copied into szHexDigest.
The maximum expected length of szHexDigest is PKI_MAX_HASH_CHARS characters.
ANSI C users must add one to this value when allocating memory.
The message digest is encoded in hexadecimal format using lower-case letters [a-f].
The message digest algorithm is indicated by the return code:
| Code | Algorithm |
|---|---|
| PKI_HASH_SHA1 (0) | SHA-1 |
| PKI_HASH_MD5 (1) | MD5 |
| PKI_HASH_MD2 (2) | MD2 |
| PKI_HASH_SHA256 (3) | SHA-256 |
| PKI_HASH_SHA384 (4) | SHA-384 |
| PKI_HASH_SHA512 (5) | SHA-512 |
| PKI_HASH_SHA224 (6) | SHA-224 |
CAUTION: unlike other hash-related functions, this function does not return the length of the digest string; it returns the code for the digest algorithm.
Note that this does not verify that the message digest is that of the content.
It does, however, verify that the message digest was indeed signed by the purported signer, but it does not check the
content itself.
To verify that the SignedData object is validly signed, the user must extract the content separately
and verify that its message digest matches the digest extracted by this function.
To do this, use the functions
CMS_ReadSigDataToString()
and HASH_HexFromBytes().
VB6 users can use HASH_HexFromString. See the examples below.
Alternatively, use the
CMS_VerifySigData()
to verify the signature and message digest directly and use
CMS_QuerySigData() to extract the messageDigest attribute, if present,
without validation.
This example extracts the message digest from the "detached signature" signed CMS object
created by CMS_MakeDetachedSig above.
Dim nDigAlg As Long
Dim strCMSFile As String
Dim strHexDigest As String
strCMSFile = "DetSignByAlice.bin"
strHexDigest = String(PKI_MAX_HASH_CHARS, " ")
nDigAlg = CMS_GetSigDataDigest(strHexDigest, Len(strHexDigest), strCMSFile, "", 0)
Debug.Print "CMS_GetSigDataDigest returns " & nDigAlg
If nDigAlg < 0 Then
Exit Function
End If
Debug.Print "Extracted digest is"
Debug.Print "[" & strHexDigest & "]"
This should produce the output
CMS_GetSigDataDigest returns 0 Extracted digest is [406aec085279ba6e16022d9e0629c0229687dd48]
This second example shows how to retrieve the message digest and independently verify this against a hash of the content.
Dim strCMSFile As String Dim strHexDigest As String Dim nDigAlg As Long Dim strData As String Dim nDataLen As Long Dim strContentDigest As String Dim nHashLen As Long strCMSFile = "4.2.bin" ' 1. Get the digest value strHexDigest = String(PKI_MAX_HASH_CHARS, " ") nDigAlg = CMS_GetSigDataDigest(strHexDigest, _ Len(strHexDigest), strCMSFile, "", 0) Debug.Print "CMS_GetSigDataDigest returns " & nDigAlg If nDigAlg < 0 Then Exit Function End If Debug.Print "Extracted digest is" Debug.Print "[" & strHexDigest & "]" ' 2. Go get the content - in this case it's in the signed-data object nDataLen = CMS_ReadSigDataToString("", 0, strCMSFile, 0) If nDataLen <= 0 Then Exit Function End If strData = String(nDataLen, " ") nDataLen = CMS_ReadSigDataToString(strData, nDataLen, strCMSFile, 0) Debug.Print "CMS_ReadSigDataToString returns " & nDataLen Debug.Print "Data is [" & strData & "]" ' 3. Compute independently the hash of what we found ' (Note how we use the digest algorithm code returned above) strContentDigest = String(PKI_MAX_HASH_CHARS, " ") nHashLen = HASH_HexFromString(strContentDigest, _ Len(strContentDigest), strData, nDataLen, nDigAlg) Debug.Print "Computed hash of content is" Debug.Print "[" & strContentDigest & "]" ' 4. Can we match this hash digest with ' what we extracted from the signed-data? strContentDigest = Left(strContentDigest, nHashLen) strHexDigest = Left(strHexDigest, nHashLen) If strContentDigest = strHexDigest Then Debug.Print "SUCCESS - digests match!" Else Debug.Print "FAILS! - no match" End If
This should produce the output
CMS_GetSigDataDigest returns 0 Extracted digest is [406aec085279ba6e16022d9e0629c0229687dd48] CMS_ReadSigDataToString returns 28 Data is [This is some sample content.] Computed hash of content is [406aec085279ba6e16022d9e0629c0229687dd48] SUCCESS - digests match!
And again, this time using C:
char *infile = "C:\\Test\\4.2.bin";
long ndigalg, mlen, hlen;
char hexdigest[41];
char conthash[41];
char *message;
/* 1. Get the digest string */
ndigalg = CMS_GetSigDataDigest(hexdigest, sizeof(hexdigest)-1,
infile, NULL, 0);
printf("CMS_GetSigDataDigest returns %ld\n", ndigalg);
if (ndigalg < 0) disp_error(ndigalg);
printf("SigDataDigest = %s\n", hexdigest);
//assert(lRet >= 0);
/* 2. Get the content from the signed-data object */
mlen = CMS_ReadSigDataToString(NULL, 0, infile, 0);
printf("Message data is %ld bytes long\n", mlen);
if (mlen < 0) disp_error(mlen);
assert(mlen >= 0);
/* Allocate some memory - NB add an extra byte */
message = malloc(mlen + 1);
assert(message);
/* Now read in */
mlen = CMS_ReadSigDataToString(message, mlen, infile, 0);
printf("CMS_ReadSigDataToString returns %ld\n", mlen);
if (mlen < 0) disp_error(mlen);
assert(mlen >= 0);
printf("Message is '%s'\n", message);
/* 3. Create a digest of this content
-- use the algorithm we got above */
hlen = HASH_HexFromBytes(conthash, sizeof(conthash)-1,
(unsigned char*)message, mlen, ndigalg);
printf("ContentDigest = %s\n", conthash);
/* 4. Finally we can compare */
if (strncmp(conthash, hexdigest, hlen) == 0)
printf("SUCCESS - digests match!\n");
else
printf("FAILS! - no match\n");
/* Clean up */
free(message);
Dim strHexDigest As String Dim strData As String Const strCMSFile As String = "4.2.bin" ' Extract the digest value strHexDigest = cmsGetSigDataDigest(strCMSFile, "") Debug.Print "extracted digest=[" & strHexDigest & "]" ' Extract content from signed-data file strData = cmsReadSigDataToString(strCMSFile) Debug.Print "content='" & strData & "'" ' Compute digest value over the content Debug.Print "computed digest =[" & hashHexFromBytes(StrConv(strData, vbFromUnicode), PKI_HASH_SHA1) & "]"
CMS_ReadSigData CMS_ReadSigDataToString CMS_QuerySigData CMS_VerifySigData
Creates a new CMS compressed-data file (.p7z) from an existing input file.
Public Declare Function CMS_MakeComprData Lib "diCrPKI.dll" (ByVal strFileOut As String, ByVal strFileIn As String, ByVal nOptions As Long) As Long
nRet = CMS_MakeComprData(strFileOut, strFileIn, nOptions) As Long
long __stdcall CMS_MakeComprData(const char *szFileOut, const char *szFileIn, long nOptions);
If successful, the return value is zero; otherwise it returns a negative error code.
static int dipki::Cms::MakeComprData (const std::string &outputFile, const std::string &inputFile)
static Cms.make_comprdata(outputfile, inputfile)
This creates a CMS compressed-data file (conventionally saved with a .p7z extension) using the zlibCompress algorithm.
It only works in file-to-file mode.
Any existing file with the same name as the parameter szFileOut will be overwritten without warning.
Note that it may not produce an exact identical output to that of another program on the same input
due to differences in ZLIB buffers and window sizes.
Dim nRet As Long Dim strBaseFile As String Dim strCompFile As String Dim strChkFile As String Dim strFileType As String strBaseFile = "sonnets.txt" strCompFile = "sonnets.p7z" ' Create a CMS compressed-data file nRet = CMS_MakeComprData(strCompFile, strBaseFile, 0) Debug.Print "CMS_MakeComprData returns " & nRet & " (expecting 0)" Debug.Print "FileLen('" & strBaseFile & "')=" & FileLen(strBaseFile) Debug.Print "FileLen('" & strCompFile & "')=" & FileLen(strCompFile) ' Check ASN.1 file type strFileType = String(PKI_ASN1_TYPE_MAXCHARS, " ") nRet = ASN1_Type(strFileType, Len(strFileType), strCompFile, 0) Debug.Print "File Type='" & Left(strFileType, nRet) & "'" ' Now check we can read it strChkFile = "sonnets-uncompr.txt" nRet = CMS_ReadComprData(strChkFile, strCompFile, 0) Debug.Print "CMS_ReadComprData returns " & nRet & " (expecting +ve)" ' And check with no-inflate option strChkFile = "sonnets-noinflate.txt" nRet = CMS_ReadComprData(strChkFile, strCompFile, PKI_CMS_NO_INFLATE) Debug.Print "CMS_ReadComprData(PKI_CMS_NO_INFLATE) returns " & nRet & " (expecting +ve)"
CMS_MakeComprData returns 0 (expecting 0)
FileLen('sonnets.txt')=106081
FileLen('sonnets.p7z')=40862
File Type='PKCS7/CMS COMPRESSED DATA '
CMS_ReadComprData returns 106081 (expecting +ve)
CMS_ReadComprData(PKI_CMS_NO_INFLATE) returns 40770 (expecting +ve)
Creates a "detached signature" CMS signed-data object from a message digest of the content.
Public Declare Function CMS_MakeDetachedSig Lib "diCrPKI.dll"
(ByVal strFileOut As String, ByVal strHexDigest As String,
ByVal strCertList As String, ByVal strPrivateKey As String,
ByVal nOptions As Long) As Long
nRet = CMS_MakeDetachedSig(strFileOut, strHexDigest,
strCertList, strPrivateKey, nOptions) As Long
long __stdcall CMS_MakeDetachedSig(const char *szFileOut, const char *szHexDigest, const char *szCertList, const char *szPrivateKey, long nOptions);
;)
If successful, the return value is zero;
otherwise it returns a nonzero error code. Further error information may be available by calling
PKI_LastError().
static int dipki::Cms::MakeDetachedSig (const std::string &outputFile, const std::string &hexDigest, const std::string &certList, const std::string &privateKey, SigAlg sigAlg=SigAlg::Default, SigDataOptions opts=SigDataOptions::Default_SigDataOpt, Format format=Format::Default)
static Cms.make_detached_sig(outputfile, hexdigest, certlist, prikeystr, sigalg=SigAlg.DEFAULT, opts=SigDataOpts.DEFAULT)
RSASSA-PKCS1V1_5 only.
See CMS_MakeSigData() for more details.
The PKI_CMS_EXCLUDE_DATA option is obviously ignored.
This example creates a "detached signature" CMS signed-data object that would duplicate a "detached signature" version of example 4.2 from [SMIME-EX] if they did one. It uses Alice's RSA private key to sign the SHA-1 Message digest of the content "This is some sample content.". The output is a BER-encoded CMS signedData object which includes her certificate but has no signed attributes.
Dim nRet As Long Dim strEPKFile As String Dim strCertFile As String Dim strOutFile As String Dim strHexDigest As String Dim strPrivateKey As String strEPKFile = "AlicePrivRSASign.p8e" strCertFile = "AliceRSASignByCarl.cer" strOutFile = "DetSignByAlice.bin" strHexDigest = "406aec085279ba6e16022d9e0629c0229687dd48" ' First, Alice reads her private key into a string strPrivateKey = rsaReadPrivateKey(strEPKFile, "password") If Len(strPrivateKey) = 0 Then MsgBox "Cannot read private key" Exit Function End If ' Alice makes a detached signature using ' the hash of the content and her private key nRet = CMS_MakeDetachedSig(strOutFile, strHexDigest, _ strCertFile, strPrivateKey, 0) Debug.Print "CMS_MakeDetachedSig returns " & nRet
CMS_MakeSigData CMS_MakeSigDataFromString
Create a CMS enveloped-data object for one or more recipients.
Public Declare Function CMS_MakeEnvData Lib "diCrPKI.dll"
(ByVal strFileOut As String, ByVal strFileIn As String,
ByVal strCertList As String, ByVal strKeyString As String, ByVal nCount As Long,
ByVal nOptions As Long) As Long
nRet = CMS_MakeEnvData(strFileOut, strFileIn,
strCertList, strKeyString, nCount, nOptions) As Long
long __stdcall CMS_MakeEnvData(const char *szFileOut, const char *szFileIn, const char *szCertList, const char *szKeyString, long nCount, long nOptions);
Special cases: Set as "type=@pwri" to create a single recipientInfo of the PasswordRecipientInfo (pwri) type;
or set as "type=@kekri,keyid=<string>" to create a single recipientInfo of the KEKRecipientInfo (kekri) type. See Remarks.
"#x<hex-digits>" to pass a string of arbitrary octet values.
Required for pwri and kekri types.
Examples: "abc" will pass the 3 bytes (0x61, 0x62, 0x63);
"#xdeadbeef01" will pass the 5 bytes (0xde, 0xad, 0xbe, 0xef, 0x01).
rsaEncryption for key transport or
ECDH with ANSI-X9.63-KDF using SHA-1 with cms3DESwrap for key agreement; and
aes128-CBC for content encryption, and output in binary format.
NOTE: some default algorithms [changed in v23.0]
To set the content encryption algorithm (default is aes128-CBC), add one of the following:
PKI_BC_AES128 to use aes128-CBC for content encryption (default as of [v23.0])
PKI_BC_AES192 to use aes192-CBC for content encryption
PKI_BC_AES256 to use aes256-CBC for content encryption
PKI_BC_3DES to use Triple-DES des-EDE3-CBC for content encryption [legacy]
PKI_AEAD_AES_128_GCM to use aes128-GCM for content encryption and authentication
PKI_AEAD_AES_192_GCM to use aes192-GCM for content encryption and authentication
PKI_AEAD_AES_256_GCM to use aes256-GCM for content encryption and authentication
PKI_AEAD_CHACHA20_POLY1305 to use AEAD_CHACHA20_POLY1305 for content encryption and authentication
To set the key transport scheme or key encapsulation mechanism (KEM) for RSA, use one of
PKI_KT_RSAES_PKCS (0) to encrypt the key using the RSAES-PKCS1-v1_5 encryption scheme rsaEncryption (default)
PKI_KT_RSAES_OAEP to encrypt the key using the RSAES-OAEP encryption scheme (see RSA signature and encryption schemes).
PKI_KEM_RSA [New in v23.0] to encrypt the key using the RSA Key Encapsulation Mechanism (RSA-KEM) algorithm
(see RSA-KEM).
To select a hash function where applicable, add one of:
PKI_HASH_SHA1 to use SHA-1 (default - CAUTION)
PKI_HASH_SHA224 to use SHA-224
PKI_HASH_SHA256 to use SHA-256 [minimum recommended]
PKI_HASH_SHA384 to use SHA-384
PKI_HASH_SHA512 to use SHA-512
If you have selected PKI_KT_RSAES_OAEP then, optionally, add
PKI_MGF_MGF1SHA1 to force the MGF hash function to be SHA-1 (default = same as encoding hash function set above)
To set the key derivation function (KDF) (where applicable), add one of:
PKI_KDF_X963 to use the ANSI-X9.63-KDF key derivation function (default for ECDH).
PKI_KDF_HKDF to use the HMAC-based Key Derivation Function (HKDF) from [RFC5869]
PKI_KDF_KDF2 to use KDF2 from ANSI-X9.44 [X9-44]
PKI_KDF_KDF3 to use KDF3 from ANSI-X9.44 (default for RSA-KEM)
and add the key wrap algorithm for the ECDH key agreement scheme or the kekri key encryption algorithm or RSA-KEM.
Default (0) is to match the key agreement algorithm to the content encryption algorithm:
PKI_KWRAP_3DES to use cms3DESwrap [legacy - only valid if Triple DES used for the content encryption algorithm].
PKI_KWRAP_AES128 to use aes128-wrap
PKI_KWRAP_AES192 to use aes192-wrap
PKI_KWRAP_AES256 to use aes256-wrap
If successful, the return value is the number of successful recipients; otherwise it returns a negative error code.
Public Function cmsMakeEnvData (szFileOut As String, szFileIn As String, szCertList As String, Optional szKeyString As String = "", Optional nOptions As Long = 0, Optional nCount As Long = 0) As Long
Cms.MakeEnvData Method ( String, String, String, CipherAlgorithm, Cms.EnvDataOptions )
Cms.MakeEnvData Method ( String, String, String, CipherAlgorithm, Cms.KeyEncrAlgorithm, HashAlgorithm, Cms.EnvDataOptions, Kdf.KdfAlg, Kdf.KeyWrapAlg, String, Int32, Cms.ContentEncrAlg )
static int dipki::Cms::MakeEnvData (const std::string &outputFile, const std::string &inputFile, const std::string &certList, CipherAlg cipherAlg=CipherAlg::Default, KeyEncrAlg keyEncrAlg=KeyEncrAlg::Default, HashAlg hashAlg=HashAlg::Default, EnvDataOptions advOpts=EnvDataOptions::Default_EnvDataOpt, Format format=Format::Default, bool bigFile=false, Kdf::KdfAlg kdfAlg=Kdf::KdfAlg::X963, Kdf::KeyWrapAlg keyWrapAlg=Kdf::KeyWrapAlg::Default, const std::string &keyString="", int count=0)
static int dipki::Cms::MakeEnvData (const std::string &outputFile, const std::string &inputFile, const std::string &schemeType, const std::string &keyString, CipherAlg cipherAlg=CipherAlg::Default, Kdf::KeyWrapAlg keyWrapAlg=Kdf::KeyWrapAlg::Default, EnvDataOptions advOpts=EnvDataOptions::Default_EnvDataOpt, Format format=Format::Default, HashAlg hashAlg=HashAlg::Default, int count=0)
static Cms.make_envdata(outputfile, inputfile, certlist, cipheralg=ContentEncrAlg.DEFAULT, keyencralg=KeyEncrAlg.DEFAULT, hashalg=0, opts=EnvDataOpts.DEFAULT, bigfile=False, kdfalg=Kdf.KdfAlg.X963, keywrapalg=0, keyString="", count=0)
The output is a file containing a CMS EnvelopedData or AuthEnvelopedData object which can be sent as part of an S/MIME message or used directly as a binary .p7m file.
The supported objects are those described in CMS Content Types.
RecipientInfo types can be KeyTransRecipientInfo (ktri), KeyAgreeRecipientInfo (kari), KEKRecipientInfo (kekri) and PasswordRecipientinfo (pwri).
If the content encryption algorithm is an authenticated encryption algorithm (AES*-GCM), then the output will be an Authenticated-Enveloped-Data object (AuthEnvelopedData) as specified in
[RFC5083] and [RFC5084].
TL;DR. The RecipientInfo type will be set according to the type of public key in the X.509 certificates. If the certificate has an RSA key, then a key-transport RecipientInfo (ktri) will be created (default PKCS#1v1.5 or RSA-OAEP if flag set). If the certificate contains a supported ECC public key, then a key-agreement type (kari) will be used (default ANSI-X9.63-KDF and keywrap to match the content encryption algorithm, HKDF if flag set). You can pass a list of mixed certificates and the appropriate RecipientInfo type will be chosen for each. There are special cases for KEK and password recipientInfo types - see below.
By default, the RecipientInfo type is set automatically depending on the public key found in each certificate in szCertList,
one for each certificate.
If the public key is RSA (rsaEncryption) then the key transport technique (ktri) will be used to create that particular recipientInfo.
If the public key is a supported ECC key, then the standard ECDH ephemeral-static key agreement technique (kari) will be used as per [RFC5753] and [RFC8418].
No checks are made on the validity period of the recipients' X.509 certificates or their key usage attributes. A PKCS#7 certificate chain file may be specified as an argument for szCertList. In which case, all certificates in the chain file will be used as recipients.
It is an error if any specified certificate file in szCertList is missing or corrupted. Call PKI_LastError() to find more details of the errors that occurred.
[New in v20.6]
RecipientInfo types KEKRecipientInfo (kekri) and PasswordRecipientinfo (pwri) are supported for a single recipient only.
For these types no certificates are required and the szCertList argument must include "type=@kekri" or "type=@pwri", respectively, all characters lower case.
In addition, for a kekri type, this argument should be of the form "type=@kekri,keyid=<string>" (Note separated by a comma ',')
where the value for the keyid attribute is used to set the keyIdentifier field in the KEKIdentifier.
This can be a simple ASCII string or can use the format "#x<hex-digits>" to pass a string of arbitrary octet values. If omitted, the default keyIdentifier is "keyid".
Optionally add a date field in the KEKIdentifier by adding a date=<iso-date-string>,
e.g. "type=@kekri,keyid=ourkeyid,date=2022-07-31T12:01".
The szKeyString argument must include either the key encryption key (KEK) for kekri or the password for pwri.
This parameter is expected to be an ASCII string. A binary KEK may be passed by using the format "#x<hex-digits>" to pass a string of arbitrary octet values.
Examples using szKeyString
nRet = CMS_MakeEnvData("xscipher_kekri.p7m", "plain.txt", "type=@kekri,keyid=oursharedkey",
"#x0123456789ABCDEFF0E1D2C3B4A59687", 0, PKI_BC_AES192 Or PKI_KWRAP_AES128);
Creates an EnvelopedData file with a single recipientInfo of type KEKRecipientInfo (kekri) with a keyid of "oursharedkey" using the 128-bit KEK
(0x)0123456789ABCDEFF0E1D2C3B4A59687 wrapped with aes128-wrap. The content is encrypted with AES-192 using a random content encryption key.
nRet = CMS_MakeEnvData("xscipher_pwri.p7m", "plain.txt", "type=@pwri",
"This is my password", 6666, PKI_BC_AES256);
Creates an EnvelopedData file with a single recipientInfo of type PasswordRecipientinfo (pwri) using the password "This is my password".
The iteration count for the KDF is 6666 (default=4096). The content is encrypted with AES-256 using a random content encryption key.
[New in v23.0] recipientInfo fields will be sorted in strict DER set sorting order. This may not be in the order of the certificates passed in szCertList.
Use the PKI_CMS_BIGFILE option flag to handle large files more efficiently.
This results in improvements of speed typically of 30% and enables, in theory, unlimited sizes of enveloped files
(subject, of course, to your level of boredom in waiting for the output). Binary output only. Not available for authenticated encryption or kekri or pwri recipientInfo types.
Specialist Option: If the PKI_CMS_ALT_ALGID option flag is present, an alternative
Content Encryption Algorithm Identifier will be used as follows:
| Default Content Encryption Algorithm Identifier | with PKI_CMS_ALT_ALGID |
|---|---|
| des-ede3-cbc (1.2.840.113549.3.7) | des_3CBC_pad (1.3.36.3.1.3.2.1) |
This alternative TeleTrusT algorithm identifier was added for compatibility with certain (superseded?) German Health profiles.
The following example reproduces example 5.1 from [SMIME-EX].
It creates an EnvelopedData CMS object for Bob from the data file
excontent.txt using Bob's X.509 certificate BobRSASignByCarl.cer.
Dim nRet As Long Dim strOutputFile As String Dim strInputFile As String Dim strCertFile As String strOutputFile = "cmsalice2bob.p7m" strInputFile = "excontent.txt" strCertFile = "BobRSASignByCarl.cer" ' This should return 1 (indicating one successful recipient) nRet = CMS_MakeEnvData(strOutputFile, strInputFile, strCertFile, "", 0, 0) Debug.Print "CMS_MakeEnvData returns " & nRet
Note that the output file will always be different from the smime-example because the content-encryption key, IV and the encrypted-content will be different each time.
The next example does the same except for two recipients: Bob and Carl.
' This should return 2 (indicating two successful recipients) nRet = CMS_MakeEnvData("cms2bobandcarl.p7m", "excontent.txt", _ "BobRSASignByCarl.cer;CarlRSASelf.cer", "", 0, 0) Debug.Print "CMS_MakeEnvData returns " & nRet
The third example is the same as the first, except it uses AES-128 instead of Triple-DES to encrypt the content.
nRet = CMS_MakeEnvData("cms2bob_aes128.p7m", "excontent.txt", _ "BobRSASignByCarl.cer", "", 0, PKI_BC_AES128) Debug.Print "CMS_MakeEnvData returns " & nRet
This example shows how to use the PKI_CMS_BIGFILE option.
Dim nRet As Long Dim strEnvDataFile As String Dim strInputFile As String Dim strCheckFile As String strEnvDataFile = "envbig.p7m" strInputFile = "bigfile.txt" Debug.Print "File " & strInputFile & "=" & FileLen(strInputFile) & " bytes" ' Make enveloped-data file: this should return 1 (indicating one successful recipient) nRet = CMS_MakeEnvData(strEnvDataFile, strInputFile, "bob.cer;", "", 0, PKI_CMS_BIGFILE) Debug.Print "CMS_MakeEnvData returns " & nRet & " (expected 1 => # recipients)" ' Now decrypt using Bob's private key Dim strPrivateKey As String strPrivateKey = rsaReadPrivateKey("bob.p8e", "password") strCheckFile = strEnvDataFile & ".out.txt" nRet = CMS_ReadEnvData(strCheckFile, strEnvDataFile, "", strPrivateKey, PKI_CMS_BIGFILE) Debug.Print "CMS_ReadEnvData returns " & nRet & " (expected 0 => success)" ' Check file length Debug.Print "File " & strCheckFile & "=" & FileLen(strCheckFile) & " bytes"
File bigfile.txt=10485700 bytes CMS_MakeEnvData returns 1 (expected 1 => # recipients) CMS_ReadEnvData returns 0 (expected 0 => success) File envbig.p7m.out.txt=10485700 bytes
Dim n As Long ' Create an enveloped CMS object (ktri type) to Bob using Bob's RSA key... n = cmsMakeEnvData("cms2bob_aes128.p7m", "excontent.txt", "BobRSASignByCarl.cer", "", PKI_BC_AES128 Or PKI_KT_RSAES_OAEP) ' Same but using authenticated encryption and creating an authEnvelopedData object... n = cmsMakeEnvData("cms2bob_aes128auth.p7m", "excontent.txt", "BobRSASignByCarl.cer", "", PKI_AEAD_AES_128_GCM Or PKI_KT_RSAES_OAEP) ' Create an enveloped CMS object (kari type) to Dana using Dana's ECC key... n = cmsMakeEnvData("cms2dana_hkdf.p7m", "excontent.txt", "lamps-dana.encrypt.crt", "", PKI_BC_AES256 Or PKI_HASH_SHA256 Or PKI_KDF_HKDF Or PKI_KWRAP_AES256) ' Create an enveloped CMS object (ktri + kari type) to Bob and Dana using respective RSA and ECC keys... n = cmsMakeEnvData("cms2bob_dana.p7m", "excontent.txt", "BobRSASignByCarl.cer;lamps-dana.encrypt.crt", "", PKI_BC_AES256 Or PKI_KT_RSAES_OAEP Or PKI_HASH_SHA256 Or PKI_KDF_HKDF) ' Create an enveloped CMS object (kekri type) using a previously distributed symmetric key-encryption key (KEK)... n = cmsMakeEnvData("cms_envdata_kekri.p7m", "excontent.txt", "type=@kekri,keyid=ourcommonkey", "#x0123456789ABCDEFF0E1D2C3B4A59687", PKI_BC_AES256 Or PKI_HASH_SHA256 Or PKI_KWRAP_AES128) ' Create an enveloped CMS object (pwri type) using password-based key management... n = cmsMakeEnvData("cms_envdata_pwri.p7m", "excontent.txt", "type=@pwri", "password12345", PKI_BC_AES192)
CMS_MakeEnvDataFromString CMS_MakeEnvDataFromBytes
Create a CMS enveloped-data object from data in a byte array.
Public Declare Function CMS_MakeEnvDataFromBytes Lib "diCrPKI.dll" (ByVal strFileOut As String, ByRef lpInput As Byte, ByVal nInputLen As Long, ByVal strCertList As String, ByVal strKeyString As String, ByVal nCount As Long, ByVal nOptions As Long) As Long
nRet = CMS_MakeEnvDataFromBytes(strFileOut, lpInput(0), nInputLen, strCertList, strKeyString, nCount, nOptions) As Long
long __stdcall CMS_MakeEnvDataFromBytes(const char *szFileOut, const unsigned char *lpInput, long nInputLen, const char *szCertList, const char *szKeyString, long nCount, long nOptions);
Special cases: Set as "type=@pwri" to create a single recipientInfo of the PasswordRecipientInfo (pwri) type;
or set as "type=@kekri,keyid=<string>" to create a single recipientInfo of the KEKRecipientInfo (kekri) type. See Remarks.
"#x<hex-digits>" to pass a string of arbitrary octet values.
Required for pwri and kekri types.
Examples: "abc" will pass the 3 bytes (0x61, 0x62, 0x63);
"#xdeadbeef01" will pass the 5 bytes (0xde, 0xad, 0xbe, 0xef, 0x01).
If successful, the return value is the number of successful recipients; otherwise it returns a negative error code.
Public Function cmsMakeEnvDataFromBytes (szFileOut As String, lpInput() As Byte, szCertList As String, Optional szKeyString As String = "", Optional nOptions As Long = 0, Optional nCount As Long = 0) As Long
Cms.MakeEnvDataFromBytes Method
static int dipki::Cms::MakeEnvDataFromBytes (const std::string &outputFile, const dipki::bvec_t &data, const std::string &certList, CipherAlg cipherAlg=CipherAlg::Default, KeyEncrAlg keyEncrAlg=KeyEncrAlg::Default, HashAlg hashAlg=HashAlg::Default, EnvDataOptions advOpts=EnvDataOptions::Default_EnvDataOpt, Format format=Format::Default, Kdf::KdfAlg kdfAlg=Kdf::KdfAlg::X963, Kdf::KeyWrapAlg keyWrapAlg=Kdf::KeyWrapAlg::Default, const std::string &ukmString="")
static Cms.make_envdata_from_bytes(outputfile, inputdata, certlist, cipheralg=ContentEncrAlg.DEFAULT, keyencralg=KeyEncrAlg.DEFAULT, hashalg=0, opts=EnvDataOpts.DEFAULT, kdfalg=Kdf.KdfAlg.X963, keywrapalg=0, keyString="", count=0)
This function is the same as CMS_MakeEnvData
except the input data is in a byte array instead of a file.
See the remarks for CMS_MakeEnvData() above.
Use this function if the plaintext contains non-ASCII characters such as UTF-8 encoded.
This example creates an enveloped-data object in a file 'cmsalice2bob_utf8.p7m'. The input is UTF-8-encoded data with some non-ASCII characters that encode to more than one byte. See CMS_ReadEnvDataToBytes for example code to read it.
Dim nRet As Long Dim strEnvDataFile As String Dim strData As String Dim abData() As Byte Dim nBytes As Long ' Input contains two non-ASCII characters: ' U+00CD Latin capital letter I with acute, encodes as (0x) C3 8D ' U+00F1 Latin small letter N with tilde, encodes as (0x) C3 B1 strData = "<doc><name c='es'>Íñigo</name></doc>" ' Convert Unicode string to UTF-8-encoded byte array nBytes = CNV_UTF8BytesFromLatin1(ByVal 0&, 0, strData) ReDim abData(nBytes - 1) nBytes = CNV_UTF8BytesFromLatin1(abData(0), nBytes, strData) Debug.Print "INPUT STR=""" & strData & """" & " (" & Len(strData) & " chars)" Debug.Print "HEX(UTF8)=" & cnvHexStrFromBytes(abData) & " (" & UBound(abData) + 1 & " bytes)" ' Create a CMS enveloped-data object using RSA-OAEP and AES-128 for content encryption strEnvDataFile = "cmsalice2bob_utf8.p7m" nRet = CMS_MakeEnvDataFromBytes(strEnvDataFile, _ abData(0), nBytes, "BobRSASignByCarl.cer", "", 0, PKI_KT_RSAES_OAEP Or PKI_BC_AES128) ' This should return 1 (indicating one successful recipient) Debug.Print "CMS_MakeEnvDataFromBytes returns " & nRet & " (= # recipients)" Debug.Assert nRet > 0 Debug.Print "Created enveloped-data file '" & strEnvDataFile & "'"
INPUT STR="<doc><name c='es'>Íñigo</name></doc>" (36 chars) HEX(UTF8)=3C646F633E3C6E616D6520633D276573273EC38DC3B169676F3C2F6E616D653E3C2F646F633E (38 bytes) CMS_MakeEnvDataFromBytes returns 1 (= # recipients) Created enveloped-data file 'cmsalice2bob_utf8.p7m'
CMS_MakeEnvData CMS_MakeEnvDataFromString CMS_ReadEnvDataToBytes
Create a CMS enveloped-data object from an ASCII string.
Public Declare Function CMS_MakeEnvDataFromString Lib "diCrPKI.dll"
(ByVal strFileOut As String, ByVal strDataIn As String,
ByVal strCertList As String, ByVal strKeyString As String, ByVal nCount As Long,
ByVal nOptions As Long) As Long
nRet = CMS_MakeEnvDataFromString(strFileOut, strDataIn, strCertList, strKeyString, nCount, nOptions) As Long
long __stdcall CMS_MakeEnvDataFromString(const char *szFileOut, const char *szDataIn, const char *szCertList, const char *szKeyString, long nCount, long nOptions);
Special cases: Set as "type=@pwri" to create a single recipientInfo of the PasswordRecipientInfo (pwri) type;
or set as "type=@kekri,keyid=<string>" to create a single recipientInfo of the KEKRecipientInfo (kekri) type. See Remarks.
"#x<hex-digits>" to pass a string of arbitrary octet values.
Required for pwri and kekri types.
Examples: "abc" will pass the 3 bytes (0x61, 0x62, 0x63);
"#xdeadbeef01" will pass the 5 bytes (0xde, 0xad, 0xbe, 0xef, 0x01).
If successful, the return value is the number of successful recipients; otherwise it returns a negative error code.
Public Function cmsMakeEnvDataFromString (szFileOut As String, szInput As String, szCertList As String, Optional szKeyString As String = "", Optional nOptions As Long = 0, Optional nCount As Long = 0) As Long
Cms.MakeEnvDataFromString Method (String, String, String, CipherAlgorithm, Cms.EnvDataOptions)
Cms.MakeEnvDataFromString Method (String, String, String, CipherAlgorithm, Cms.KeyEncrAlgorithm, HashAlgorithm, Cms.EnvDataOptions, Kdf.KdfAlg, Kdf.KeyWrapAlg, String, Int32, Cms.ContentEncrAlg)
static int dipki::Cms::MakeEnvDataFromString (const std::string &outputFile, const std::string &inputStr, const std::string &certList, CipherAlg cipherAlg=CipherAlg::Default, KeyEncrAlg keyEncrAlg=KeyEncrAlg::Default, HashAlg hashAlg=HashAlg::Default, EnvDataOptions advOpts=EnvDataOptions::Default_EnvDataOpt, Format format=Format::Default, Kdf::KdfAlg kdfAlg=Kdf::KdfAlg::X963, Kdf::KeyWrapAlg keyWrapAlg=Kdf::KeyWrapAlg::Default, const std::string &ukmString="")
static Cms.make_envdata_from_string(outputfile, inputdata, certlist, cipheralg=ContentEncrAlg.DEFAULT, keyencralg=KeyEncrAlg.DEFAULT, hashalg=0, opts=EnvDataOpts.DEFAULT, kdfalg=Kdf.KdfAlg.X963, keywrapalg=0, keyString="", count=0)
This function is the same as CMS_MakeEnvData
except the input data is in an ASCII string instead of a file.
See the remarks for CMS_MakeEnvData() above.
Use this function only when the plaintext is only plain ASCII text,
otherwise use CMS_MakeEnvDataFromBytes.
The following example reproduces example 5.2 from SMIME-EX (as far as it can, because of the different random values used each time) passing the input data as a string. The output is always a new file.
' This should return 1 (indicating one successful recipient) nRet = CMS_MakeEnvDataFromString("cmsalice2bob1.p7m", _ "This is some sample content.", "BobRSASignByCarl.cer", "", 0, 0) Debug.Print "CMS_MakeEnvDataFromString returns " & nRet
Dim strCertList As String Dim strCmsFile As String Dim nRet As Long Dim strQuery As String ' Use Dana's X22519 certificate strCmsFile = "dana_alice_hkdf.p7m" strCertList = "lamps-dana.encrypt.crt" ' Use AES256 for content encryption and Ephemeral-Static ECDH key agreement using HKDF key derivation function with SHA-256 and aes256-wrap nRet = cmsMakeEnvDataFromString(strCmsFile, "This is some sample content.", strCertList, "", PKI_BC_AES256 Or PKI_HASH_SHA256 Or PKI_KDF_HKDF Or PKI_KWRAP_AES256) Debug.Print "cmsMakeEnvDataFromString returns " & nRet & " (expecting 1)" ' Query EnvelopedData file Debug.Print "FILE: " & strCmsFile strQuery = "contentEncryptionAlgorithm" Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery) strQuery = "keyEncryptionAlgorithm" Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery) strQuery = "keyWrapAlgorithm" Debug.Print "QueryEnvData('" & strQuery & "')=" & cmsQueryEnvData(strCmsFile, strQuery)
cmsMakeEnvDataFromString returns 1 (expecting 1)
FILE: dana_alice_hkdf.p7m
QueryEnvData('contentEncryptionAlgorithm')=aes256-CBC
QueryEnvData('keyEncryptionAlgorithm')=ecdhHKDF-SHA256
QueryEnvData('keyWrapAlgorithm')=aes256-wrap
CMS_MakeEnvData CMS_MakeEnvDataFromBytes
Creates a CMS object of type SignedData from an input data file.
Public Declare Function CMS_MakeSigData Lib "diCrPKI.dll"
(ByVal strFileOut As String, ByVal strFileIn As String,
ByVal strCertList As String, ByVal strPrivateKey As String, ByVal nOptions As Long) As Long
nRet = CMS_MakeSigData(strFileOut, strFileIn, strCertList, strPrivateKey, nOptions) As Long
long __stdcall CMS_MakeSigData(const char *szFileOut, const char *szFileIn, const char *szCertList, const char *szPrivateKey, long nOptions);
sha1WithRSAEncryption) (default - CAUTION)sha224WithRSAEncryption)sha256WithRSAEncryption) [minimum recommended]sha384WithRSAEncryption)sha512WithRSAEncryption)md5WithRSAEncryption) [legacy, not recommended for new implementations]ecdsaWithSHA1ecdsaWithSHA224ecdsaWithSHA256ecdsaWithSHA384ecdsaWithSHA512Ed25519 [New in v20.0]Ed448 [New in v22.0]PKI_CMS_INCLUDE_ATTRS option flag is included, optionally add any of the following:
If successful, the return value is zero;
otherwise it returns a nonzero error code. Further error information may be available by calling
PKI_LastError().
Cms.MakeSigData Method ( String, String, String, String, Cms.SigAlg, Cms.SigDataOptions)
Cms.MakeSigData Method ( String, String, String, String, HashAlgorithm, Cms.SigDataOptions)
static int dipki::Cms::MakeSigData (const std::string &outputFile, const std::string &inputFile, const std::string &certList, const std::string &privateKey, SigAlg sigAlg=SigAlg::Default, SigDataOptions opts=SigDataOptions::Default_SigDataOpt, Format format=Format::Default, bool bigFile=false)
static Cms.make_sigdata(outputfile, inputfile, certlist, prikeystr, sigalg=SigAlg.DEFAULT, opts=SigDataOpts.DEFAULT, bigfile=False)
A SignedData CMS object with a single SignerInfo is created with the message data included by default in the eContent.
The signer's certificate must be included in the certificate list.
All certificates in the list will be included in the output by default.
Signed attributes are not included by default but can be added by using the PKI_CMS_INCLUDE_ATTRS option flag (see below).
Unsigned attributes and attribute certificates are not supported.
The default signature algorithm is RSASSA-PKCS-v1_5 with SHA-1 (SHA-1 caution!).
The message digest algorithm always matches the digest algorithm used in the signature.
The encapContentInfo eContentType is always id-data: other eContentTypes are not possible.
Only one SignerInfo can be included at one time, but [New in v23.0]
additional SignerInfos can be added by calling this function second time passing an existing SignedData object as input and setting the PKI_CMS_ADD_SIGNER (see below).
[New in v23.0] The signer's public key can be referenced using either issuerAndSerialNumber (default)
or subjectKeyIdentifier (use the PKI_CMS_USE_SKI option).
If subjectKeyIdentifier is used then the CMSversion will be 3 and the relevant SignerInfo version will also be 3.
Otherwise the CMSVersion will be 1 and the SignerInfo structure also version 1.
It is an error (NO_MATCH_ERROR) if the private key does not match any certificate in the certificate list.
[New in v23.0] signerInfo and CertificateSet fields will be sorted in strict DER set sorting order. This may not be in the order of the certificates passed in szCertList or added using PKI_CMS_ADD_SIGNER.
PKI_CMS_CERTS_ONLY: To create a PKCS#7 certificate chain
(a degenerate "certs-only" signed data object), include the option flag PKI_CMS_CERTS_ONLY.
The szCertList can contain references to any existing certificate files in any order, separated by semi-colons.
The szFileIn and szPrivateKey parameters are ignored and can be left empty.
See the second example below.
PKI_CMS_INCLUDE_ATTRS:
Signed attributes are not included by default. To add signed attributes use the PKI_CMS_INCLUDE_ATTRS option flag.
This will add the content-type and message-digest attributes plus any other attributes specified using a PKI_CMS_ADD_* option.
PKI_CMS_ADD_SIGNINGCERT: [New in v12.4] Include the PKI_CMS_ADD_SIGNINGCERT option to add an ESS Signing Certificate Attribute to the signed attributes. This is required for B-level compliance with CAdES-BES [CADES] and with ESS [RFC2634] and [RFC5035].
PKI_CMS_ADD_ALGPROTECT: [New in v12.4] Include the PKI_CMS_ADD_ALGPROTECT option to add an Algorithm Protection Attribute to the signed attributes. This is in accordance with [RFC6211]. If a CMS validator supports this attribute, then additional checks can be made against algorithm substitution attacks.
PKI_CMS_BIGFILE: Include the PKI_CMS_BIGFILE option to cope more efficiently with large files. This only works in binary-file-to-binary-file mode, and only for RSA signatures, but makes a significant difference in processing times. The option flags PKI_CMS_EXCLUDE_DATA, PKI_CMS_CERTS_ONLY, PKI_CMS_FORMAT_BASE64, and PKI_CMS_NO_OUTER are not permitted with this option.
PKI_CMS_ADD_SIGNER: [New in v23.0] To sign an existing SignedData object with another signature, use the PKI_CMS_ADD_SIGNER option and pass the existing SignedData object as the input data file. Pass the signer's certificate in szCertList (plus any additional certificates if required) and the signer's private key string in szPrivateKey.
PKI_PSS_SALTLEN_ZERO: [New in v12.0]
Include the PKI_PSS_SALTLEN_ZERO with an RSA-PSS scheme to set the salt length parameter to be zero. This results in a deterministic signature value.
The default salt length is otherwise always hLen, the length of the output of the hash function.
There are no other salt length options available for this function. See RSA signature and encryption schemes.
PKI_CMS_ALT_ALGID:
If the PKI_CMS_ALT_ALGID option flag is present, an alternative
Signature Algorithm Identifier will be used as follows (RSAES-PKCS-v1_5 only):
| Message Digest Algorithm | Default Signature Algorithm Identifier | Alternative ID with PKI_CMS_ALT_ALGID |
|---|---|---|
SHA-1 (default, PKI_SIG_RSA_SHA1) | rsaEncryption (1.2.840.113549.1.1) | sha1withRSAEncryption (1.2.840.113549.1.1.5) |
MD5 (with PKI_SIG_RSA_MD5) | rsaEncryption (1.2.840.113549.1.1) | md5withRSAEncryption (1.2.840.113549.1.1.4) |
SHA-224 (with PKI_SIG_RSA_SHA224) | rsaEncryption (1.2.840.113549.1.1) | sha224withRSAEncryption (1.2.840.113549.1.1.14) |
SHA-256 (with PKI_SIG_RSA_SHA256) | rsaEncryption (1.2.840.113549.1.1) | sha256withRSAEncryption (1.2.840.113549.1.1.11) |
SHA-384 (with PKI_SIG_RSA_SHA384) | rsaEncryption (1.2.840.113549.1.1) | sha384withRSAEncryption (1.2.840.113549.1.1.12) |
SHA-512 (with PKI_SIG_RSA_SHA512) | rsaEncryption (1.2.840.113549.1.1) | sha512withRSAEncryption (1.2.840.113549.1.1.13) |
The default is to use the rsaEncryption identifier specified in Section 3.2 of [CMSALG].
PKI_CMS_PSEUDOSIG: [New in v20.2] Include the PKI_CMS_PSEUDOSIG option to create a create a "pseudo" SignedData object. The idea here is that we create an intermediate file which has the same structure as a CMS SignedData object except the signature is a dummy placeholder. We use the term "pseudo" file here to describe this intermediate file.
This pseudo file has the same digest value as the final signed object (as the digest is not calculated over the final signature). We send this digest value to a signing authority (say, Aruba), they sign it, and send back the actual signature value. This can be substituted in the intermediate pseudo file to produce the final SignedData object (.p7m file) using CMS_MakeSigDataFromSigValue with the PKI_CMS_PSEUDOSIG option. RSASSA-PKCS1V1_5 only.
Specialist Option: If the PKI_CMS_NO_OUTER option flag is present, the output will be a "naked"
SignedData object without an outerContentInfo.
This is not permitted by the CMS standard [CMS]
but is allowed by PKCS#7 version 1.6 [PKCS7-EXT].
Some profiles (e.g. Royal Thai Customs) require this.
This example duplicates example 4.2 from [SMIME-EX]. It uses Alice's RSA private key to sign the message stored in the file excontent.txt (which contains the text "This is some sample content."). The output is a binary BER-encoded CMS signedData object which includes her certificate and the data but has no signed attributes. The output file should match the file 4.2.bin from [SMIME-EX].
Dim strPriFile As String Dim strPrivateKey As String Dim nIntKeyLen As Long Dim nRet As Long Dim strInputFile As String Dim strOutputFile As String Dim strCertFile As String strPriFile = "AlicePrivRSASign.pri" strCertFile = "AliceRSASignByCarl.cer" strInputFile = "excontent.txt" strOutputFile = "BasicSignByAlice.bin" ' First we need to read in the private key string ' NB: This version is not encrypted, so no password needed nIntKeyLen = RSA_ReadAnyPrivateKey("", 0, strPriFile, "", 0) Debug.Print "nIntKeyLen = " & nIntKeyLen If nIntKeyLen <= 0 Then Debug.Print pkiGetLastError() MsgBox "Unable to retrieve private key" Exit Sub End If ' Pre-dimension the string to receive data strPrivateKey = String(nIntKeyLen, " ") ' Read in the Private Key nRet = RSA_ReadAnyPrivateKey(strPrivateKey, nIntKeyLen, strPriFile, "", 0) Debug.Print "Key size=" & RSA_KeyBits(strPrivateKey) & " bits" ' Now we can sign our message nRet = CMS_MakeSigData(strOutputFile, strInputFile, strCertFile, strPrivateKey, 0) Debug.Print "CMS_MakeSigData returns " & nRet
In this second example, we create a PKCS#7 certficate chain file containing Carl's and Alice's X.509 certificates.
Dim nRet As Long Dim strOutputFile As String Dim strCertList As String ' Make a list of certs separated by semi-colons (;) strCertList = "CarlRSASelf.cer;" & "AliceRSASignByCarl.cer" Debug.Print "CertList=" & strCertList strOutputFile = "SigDataCertsOnly.p7c" ' Create a certs-only .p7c chain nRet = CMS_MakeSigData(strOutputFile, "", strCertList, "", PKI_CMS_CERTS_ONLY) Debug.Print "CMS_MakeSigData returns " & nRet If nRet <> 0 Then Debug.Print pkiGetLastError()
CMS_MakeSigDataFromString CMS_MakeSigDataFromSigValue CMS_MakeDetachedSig
Creates a CMS object of type SignedData using a pre-computed signature value.
Public Declare Function CMS_MakeSigDataFromSigValue Lib "diCrPKI.dll"
(ByVal strFileOut As String, ByRef lpSigValue As Byte, ByVal nSigLen As Long,
ByRef lpData As Byte, ByVal nDataLen As Long,
ByVal strCertList As String, ByVal nOptions As Long) As Long
nRet = CMS_MakeSigDataFromSigValue(strFileOut, lpSigValue(0), nSigLen,
lpData(0), nDataLen, strCertList, nOptions) As Long ' Note the "(0)" after the byte array parameters
long __stdcall CMS_MakeSigDataFromSigValue(const char *szFileOut, const unsigned char *lpSigValue, long nSigLen, const unsigned char *lpData, long nDataLen, const char *szCertList, long nOptions);
CMS_MakeSigData())
If successful, the return value is zero;
otherwise it returns a nonzero error code. Further error information may be available by calling
PKI_LastError().
Public Function cmsMakeSigDataFromSigValue (szFileOut As String, lpSigValue() As Byte, lpInput() As Byte, szCertList As String, Optional nOptions As Long = 0) As Long
Cms.MakeSigDataFromSigValue Method
Cms.MakeSigDataFromPseudo Method
static int dipki::Cms::MakeSigDataFromSigValue (const std::string &outputFile, const dipki::bvec_t &sigValue, const dipki::bvec_t &data, const std::string &certList, SigAlg sigAlg=SigAlg::Default, SigDataOptions opts=SigDataOptions::Default_SigDataOpt, Format format=Format::Default)
static Cms.make_sigdata_from_sigvalue(outputfile, sigvalue, data, certlist, sigalg=SigAlg.DEFAULT, opts=SigDataOpts.DEFAULT)
static Cms.make_sigdata_from_pseudo(outputfile, inputfile, sigvalue, opts=SigDataOpts.DEFAULT)
static Cms.make_sigdata_from_pseudo(outputfile, inputfile, sigvalue, opts=SigDataOpts.DEFAULT)
static Cms.make_sigdata_from_sigvalue(outputfile, sigvalue, data, certlist, sigalg=SigAlg.DEFAULT, opts=SigDataOpts.DEFAULT)
static Cms.make_sigdata_from_pseudo(outputfile, inputfile, sigvalue, opts=SigDataOpts.DEFAULT)
This is a specialized option for a specific case where the RSA v1.5 signature value over the content has been computed separately (say, using a smart card) and the user requires this to be used inside a CMS signed-data object.
A SignedData CMS object with a single SignerInfo is created with the message data included in the eContent.
Signed attributes cannot be added. Unsigned attributes and attribute certificates are not supported.
The content must be included in the input using the lpData and nDataLen parameters.
Only RSASSA-PKCS-v1_5 signature schemes are supported by this function.
Only one message digest algorithm is used in each object. SHA-1 is used by default.
Alternative hash algorithms can be used instead by adding the appropriate PKI_HASH_ option flag (this must match the digest algorithm used to compute the signature).
The content and the signature are checked before the output file is created. If the signature data is not valid,
or the data is not the data signed, or the certificate specified is not that of the signer, then
it will return SIGNATURE_ERROR (-22).
[New in v12.2] A PKCS#7 certificate chain file (.p7c/.p7b) may be specified as an argument for szCertList. The signer's certificate can now exist anywhere in the certificate list (previously it had to be the first).
[New in v20.2] Use the PKI_CMS_PSEUDOSIG option to create a SignedData object from a "pseudo" object, created using CMS_MakeSigData with the PKI_CMS_PSEUDOSIG option.
This example creates an identical SignedData file to example 4.2 from [SMIME-EX].
In this case, the signature value has been generated separately, perhaps by a smart card with Alice's private
key details in it. The resulting file should be identical to the file 4.2.bin.
Dim strDataHex As String Dim strSigHex As String Dim abData() As Byte Dim abSigValue() As Byte Dim nSigLen As Long Dim nDataLen As Long Dim strCertFile As String Dim strCmsFile As String Dim nRet As Long ' Data to be signed in hex format: strDataHex = "54:68:69:73:20:69:73:20:73:6f:6d:65:20:73:61:6d" & _ "70:6c:65:20:63:6f:6e:74:65:6e:74:2e" ' The signature (generated by the smart card) is: strSigHex = "2F:23:82:D2:F3:09:5F:B8:0C:58:EB:4E:9D:BF:89:9A" & _ "81:E5:75:C4:91:3D:D3:D0:D5:7B:B6:D5:FE:94:A1:8A" & _ "AC:E3:C4:84:F5:CD:60:4E:27:95:F6:CF:00:86:76:75" & _ "3F:2B:F0:E7:D4:02:67:A7:F5:C7:8D:16:04:A5:B3:B5" & _ "E7:D9:32:F0:24:EF:E7:20:44:D5:9F:07:C5:53:24:FA" & _ "CE:01:1D:0F:17:13:A7:2A:95:9D:2B:E4:03:95:14:0B" & _ "E9:39:0D:BA:CE:6E:9C:9E:0C:E8:98:E6:55:13:D4:68" & _ "6F:D0:07:D7:A2:B1:62:4C:E3:8F:AF:FD:E0:D5:5D:C7" strCertFile = "AliceRSASignByCarl.cer" strCmsFile = "BasicSignByAliceExternal.bin" ' Convert the hex strings into byte arrays (non-hex chars are stripped) abData = cnvBytesFromHexStr(strDataHex) abSigValue = cnvBytesFromHexStr(strSigHex) ' Compute lengths nDataLen = UBound(abData) - LBound(abData) + 1 nSigLen = UBound(abSigValue) - LBound(abSigValue) + 1 ' Create the signed-data file nRet = CMS_MakeSigDataFromSigValue(strCmsFile, abSigValue(0), _ nSigLen, abData(0), nDataLen, strCertFile, 0) Debug.Print "CMS_MakeSigDataFromSigValue returns " & nRet
To compare the output file to the reference file, use the Windows FC command:
C:> FC BasicSignByAliceExternal.bin 4.2.bin
Comparing files BasicSignByAliceExternal.bin and 4.2.BIN FC: no differences encountered
CMS_MakeSigData CMS_MakeDetachedSig
Create a CMS object of type SignedData from an array of bytes.
Public Declare Function CMS_MakeSigDataFromBytes Lib "diCrPKI.dll" (ByVal strFileOut As String, ByRef lpInput As Byte, ByVal nInputLen As Long, ByVal strCertList As String, ByVal strPrivateKey As String, ByVal nOptions As Long) As Long
nRet = CMS_MakeSigDataFromBytes(strFileOut, lpInput(0), nInputLen, strCertList, strPrivateKey, nOptions) As Long
long __stdcall CMS_MakeSigDataFromBytes(const char *szFileOut, const unsigned char *lpInput, long nInputLen, const char *szCertList, const char *szPrivateKey, long nOptions);
sha1WithRSAEncryption) (default - CAUTION)sha224WithRSAEncryption)sha256WithRSAEncryption) [minimum recommended]sha384WithRSAEncryption)sha512WithRSAEncryption)md5WithRSAEncryption) [legacy, not recommended for new implementations]ecdsaWithSHA1ecdsaWithSHA224ecdsaWithSHA256ecdsaWithSHA384ecdsaWithSHA512Ed25519 [New in v20.0]Ed448 [New in v22.0]PKI_CMS_INCLUDE_ATTRS option flag is included, optionally add any of the following:
If successful, the return value is zero;
otherwise it returns a nonzero error code. Further error information may be available by calling
PKI_LastError().
Public Function cmsMakeSigDataFromBytes (szFileOut As String, lpInput() As Byte, szCertList As String, szPrivateKey As String, Optional nOptions As Long = 0) As Long
Cms.MakeSigDataFromBytes Method
static int dipki::Cms::MakeSigDataFromBytes (const std::string &outputFile, const dipki::bvec_t &data, const std::string &certList, const std::string &privateKey, SigAlg sigAlg=SigAlg::Default, SigDataOptions opts=SigDataOptions::Default_SigDataOpt, Format format=Format::Default)
static Cms.make_sigdata_from_bytes(outputfile, inputdata, certlist, prikeystr, sigalg=SigAlg.DEFAULT, opts=SigDataOpts.DEFAULT)
static Cms.make_sigdata_from_string(outputfile, inputstr, certlist, prikeystr, sigalg=SigAlg.DEFAULT, opts=SigDataOpts.DEFAULT)
static Cms.make_sigdata_from_bytes(outputfile, inputdata, certlist, prikeystr, sigalg=SigAlg.DEFAULT, opts=SigDataOpts.DEFAULT)
This function is identical to
CMS_MakeSigData()
except the input is passed as a byte array instead of in a file.
See the remarks for CMS_MakeSigData above.
Use this function if the content contains non-ASCII characters such as UTF-8 encoded.
This example creates an signed-data object in a file 'basicsignedbyalice_utf8.p7m'.
The input is UTF-8-encoded data with some non-ASCII characters that encode to more than one byte.
See CMS_ReadSigDataToBytes for example code to read it.
Dim nRet As Long
Dim strSigDataFile As String
Dim strData As String
Dim abData() As Byte
Dim nBytes As Long
Dim strPrivateKey As String
' Input contains two non-ASCII characters:
' U+00CD Latin capital letter I with acute, encodes as (0x) C3 8D
' U+00F1 Latin small letter N with tilde, encodes as (0x) C3 B1
strData = "<doc><name c='es'>Íñigo</name></doc>"
' Convert Unicode string to UTF-8-encoded byte array
nBytes = CNV_UTF8BytesFromLatin1(ByVal 0&, 0, strData)
ReDim abData(nBytes - 1)
nBytes = CNV_UTF8BytesFromLatin1(abData(0), nBytes, strData)
Debug.Print "INPUT STR=""" & strData & """" & " (" & Len(strData) & " chars)"
Debug.Print "HEX(UTF8)=" & cnvHexStrFromBytes(abData) & " (" & UBound(abData) + 1 & " bytes)"
' We need Alice's private key
strPrivateKey = rsaReadPrivateKey("AlicePrivRSASign.p8e", "password")
If Len(strPrivateKey) = 0 Then
MsgBox "Cannot read private key"
Exit Sub
End If
' Create a CMS signed-data object
strSigDataFile = "basicsignedbyalice_utf8.p7m"
nRet = CMS_MakeSigDataFromBytes(strSigDataFile, _
abData(0), nBytes, "AliceRSASignByCarl.cer", strPrivateKey, PKI_SIG_RSA_PSS_SHA256)
' This should return 0 indicating success
Debug.Print "CMS_MakeSigDataFromBytes returns " & nRet & " (expected 0)"
Debug.Assert 0 = nRet
Debug.Print "Created signed-data file '" & strSigDataFile & "'"
CleanUp:
wipeString strPrivateKey
INPUT STR="<doc><name c='es'>Íñigo</name></doc>" (36 chars) HEX(UTF8)=3C646F633E3C6E616D6520633D276573273EC38DC3B169676F3C2F6E616D653E3C2F646F633E (38 bytes) CMS_MakeSigDataFromBytes returns 0 (expected 0) Created signed-data file 'basicsignedbyalice_utf8.p7m'
Dim strSigDataFile As String Dim strCertFile As String Dim lpData() As Byte Dim strPrivateKey As String Dim strQuery As String Dim r As Long ' Input contains two non-ASCII characters: ' U+00CD Latin capital letter I with acute, encodes as (0x) C3 8D ' U+00F1 Latin small letter N with tilde, encodes as (0x) C3 B1 ' Convert Unicode string to UTF-8-encoded byte array to be signed lpData = cnvUTF8BytesFromLatin1("<doc><name c='es'>Íñigo</name></doc>") Debug.Print "HEX(data to be signed)=" & cnvToHex(lpData) ' Read in Dana's ED25519 private key strPrivateKey = eccReadPrivateKey("lamps-dana.p8.pem", "") strCertFile = "lamps-dana.crt" ' Create a CMS signed-data object strSigDataFile = "signeddata-utf8-dana.p7m" r = cmsMakeSigDataFromBytes(strSigDataFile, lpData, strCertFile, strPrivateKey, PKI_SIG_ED25519 Or PKI_CMS_INCLUDE_ATTRS Or PKI_CMS_ADD_SIGNINGCERT) Debug.Print "cmsMakeSigDataFromBytes returns " & r & " (expected 0)" Debug.Assert 0 = r Debug.Print "FILE: " & strSigDataFile ' Query the signed-data object strQuery = "signatureAlgorithm" Debug.Print "QuerySigData('" & strQuery & "')=" & cmsQuerySigData(strSigDataFile, strQuery) strQuery = "signingCertHash" Debug.Print "QuerySigData('" & strQuery & "')=" & cmsQuerySigData(strSigDataFile, strQuery) ' Check thumbprint of cert, this should match the signingCertHash Debug.Print "CertThumb=" & x509CertThumb(strCertFile) ' Read back the signed data lpData = cmsReadSigDataToBytes(strSigDataFile) Debug.Print "HEX(recovered content)=" & cnvToHex(lpData)
HEX(data to be signed)=3C646F633E3C6E616D6520633D276573273EC38DC3B169676F3C2F6E616D653E3C2F646F633E
cmsMakeSigDataFromBytes returns 0 (expected 0)
FILE: signeddata-utf8-dana.p7m
QuerySigData('signatureAlgorithm')=Ed25519
QuerySigData('signingCertHash')=4db09e5f691aeaf46bffa1dbd4719d5c3f529ca0
CertThumb=4db09e5f691aeaf46bffa1dbd4719d5c3f529ca0
HEX(recovered content)=3C646F633E3C6E616D6520633D276573273EC38DC3B169676F3C2F6E616D653E3C2F646F633E
CMS_MakeSigData CMS_MakeSigDataFromString CMS_MakeDetachedSig
Create a CMS object of type SignedData from an input string.
Public Declare Function CMS_MakeSigDataFromString Lib "diCrPKI.dll"
(ByVal strFileOut As String, ByVal strDataIn As String,
ByVal strCertList As String, ByVal strPrivateKey As String, ByVal nOptions As Long) As Long
nRet = CMS_MakeSigDataFromString(strFileOut, strDataIn,
strCertList, strPrivateKey, nOptions) As Long
long __stdcall CMS_MakeSigDataFromString(const char *szFileOut, const char *szDataIn, const char *szCertList, const char *szPrivateKey, long nOptions);
sha1WithRSAEncryption) (default - CAUTION)sha224WithRSAEncryption)sha256WithRSAEncryption) [minimum recommended]sha384WithRSAEncryption)sha512WithRSAEncryption)md5WithRSAEncryption) [legacy, not recommended for new implementations]ecdsaWithSHA1ecdsaWithSHA224ecdsaWithSHA256ecdsaWithSHA384ecdsaWithSHA512Ed25519 [New in v20.0]Ed448 [New in v22.0]PKI_CMS_INCLUDE_ATTRS option flag is included, optionally add any of the following:
If successful, the return value is zero;
otherwise it returns a nonzero error code. Further error information may be available by calling
PKI_LastError().
Cms.MakeSigDataFromString Method (String, String, String, String, Cms.SigAlg, Cms.SigDataOptions)
Cms.MakeSigDataFromString Method (String, String, String, String, HashAlgorithm, Cms.SigDataOptions)
static int dipki::Cms::MakeSigDataFromString (const std::string &outputFile, const std::string &inputStr, const std::string &certList, const std::string &privateKey, SigAlg sigAlg=SigAlg::Default, SigDataOptions opts=SigDataOptions::Default_SigDataOpt, Format format=Format::Default)
This function is identical to
CMS_MakeSigData()
except the input is passed as a string instead of in a file.
Zero-terminated ANSI data is expected in szDataIn.
VB6 users: the string szDataIn must not contain a NUL (Chr$(0)) character.
To sign a messsage that contains binary or Unicode UTF-8 or UTF-16 data, use
CMS_MakeSigDataFromBytes.
nRet = CMS_MakeSigDataFromString(strOutputFile, "This is some sample content.", _
strCertFile, strPrivateKey, 0)
CMS_MakeSigData CMS_MakeSigDataFromBytes CMS_MakeDetachedSig
Queries a CMS enveloped-data object file for selected information.
Public Declare Function CMS_QueryEnvData Lib "diCrPKI.dll"
(ByVal strDataOut As String, ByVal nDataLen As Long,
ByVal strFileIn As String, ByVal strQuery As String, ByVal nOptions As Long) As Long
nRet = CMS_QueryEnvData(strDataOut, nDataLen, strFileIn, strQuery,
nOptions) As Long
long __stdcall CMS_QueryEnvData(char *szOutput, long nOutChars, const char *szFileIn, const char *szQuery, long nOptions);
If successful, the return value is a positive integer indicating either the result itself (if the result is a number) or the number of characters in the output string (if the query is looking for a string). If the item queried cannot be found, the return value is zero. If there is an error (e.g. an invalid signed-data file), it returns a negative error code.
Public Function cmsQueryEnvData (szFileIn As String, szQuery As String, Optional nOptions As Long = 0) As String
static std::string dipki::Cms::QueryEnvData (const std::string &inputFile, const std::string &query)
static Cms.query_envdata(cmsfile, query)
This function queries a given EnvelopedData file for selected information.
The query string is case-insensitive, so "version", "VERSION" and "VeRsIoN" are all valid.
Valid queries are (case-insensitive):
| Query String | Returns | Data Type |
|---|---|---|
version | envelopedData CMSVersion (edVer) value | Number |
recipientInfoVersion | recipientInfo version (riVer) value | Number |
recipientInfoType | Type of recipientInfo: ktri, kari, kekri, pwri, ori | String |
CountOfRecipientInfos | Number of RecipientInfos included in the data | Number |
recipientIssuerName | Distinguished Name of recipient's certificate issuer | String |
recipientSerialNumber | serialNumber of recipient's certificate in hex format | String |
keyEncryptionAlgorithm | keyEncryptionAlgorithm, e.g. "rsaEncryption" | String |
keyEncryptionFlags | Bit flags used for the key encryption algorithm (ktri only) | Number |
SizeOfEncryptedKey | Size (in bytes) of the EncryptedKey | Number |
encryptedKey | EncryptedKey value encoded in hex | String |
oaepParams | Parameters used for RSA-OAEP (if applicable). | String |
kemParams | Parameters used for RSA-KEM (if applicable) [New in v23.0] | String |
keyWrapAlgorithm | Key wrap algorithm, e.g. "aes128-wrap" (kari and kekri only) | String |
originatorKeyAlgorithm | OriginatorPublicKey algorithm, e.g. "ecPublicKey" (kari only) | String |
originatorPublicKey | OriginatorPublicKey publicKey value encoded in hex (kari only) | String |
keyid | keyIdentifier for KEKRecipientInfo (kekri) type | String |
ukm | User Keying Material (if applicable) [New in v23.0] | String |
contentEncryptionAlgorithm | contentEncryptionAlgorithm, e.g. "des-EDE3-CBC" | String |
SizeOfEncryptedContent | Size (in bytes) of the EncryptedContent | Number |
encryptedContent | EncryptedContent encoded in hex | String |
iv | Initialization vector for encrypted content encoded in hex | String |
HASsubjectKeyIdentifier | 1 if recipientIdentifier is the CHOICE subjectKeyIdentifier; 0 if issuerAndSerialNumber [New in v23.0] | Number |
recipientIdentifier | recipientIdentifier value encoded in hex [New in v23.0] | String |
By default, the function queries the first recipientInfo in the file.
To query the Nth recipientInfo append "/N" to the query string, e.g.
"recipientInfoVersion/2" to find the version number of the second recipientInfo in the file.
The query encryptedContent may be slow to respond if the file is large.
The "raw" VBA/C function behaves differently depending on whether the output is a string or a number. If the result data type is a number then it returns the value directly. If the result is a string, then it sets szOutput and returns the number of characters in the string. The required number of characters can be found by passing zero for nOutChars or a null string for szOutput. ANSI C users must add one to this value when allocating memory.
Note that the VBA wrapper function and the C#/VB.NET and C++ (STL) methods always return a string, which is different from the behaviour of the raw VB6/C function.
To find out the type of data returned for a given query, use the PKI_QUERY_GETTYPE option.
The function will return either PKI_QUERY_NUMBER (1) or PKI_QUERY_STRING (2),
or a negative "invalid query" error.
For example
nRet = CMS_QueryEnvData("", 0, "", "version", PKI_QUERY_GETTYPE);
will return PKI_QUERY_NUMBER.
This example queries information from various sample files.
Dim strCmsFile As String Dim nRet As Long Dim strOutput As String Dim strQuery As String ' Pre-dimension output string strOutput = String(64, " ") strCmsFile = "5.1.bin" Debug.Print "File " & strCmsFile & "..." strQuery = "version" nRet = CMS_QueryEnvData(vbNullString, 0, strCmsFile, strQuery, 0) Debug.Print strQuery & "=" & nRet strQuery = "contentEncryptionAlgorithm" nRet = CMS_QueryEnvData(strOutput, Len(strOutput), strCmsFile, strQuery, 0) If nRet > 0 Then Debug.Print strQuery & "=" & Left$(strOutput, nRet) End If strQuery = "sizeofEncryptedContent" nRet = CMS_QueryEnvData(vbNullString, 0, strCmsFile, strQuery, 0) Debug.Print strQuery & "=" & nRet strQuery = "countOfRecipientInfos" nRet = CMS_QueryEnvData(vbNullString, 0, strCmsFile, strQuery, 0) Debug.Print strQuery & "=" & nRet strQuery = "keyEncryptionAlgorithm" nRet = CMS_QueryEnvData(strOutput, Len(strOutput), strCmsFile, strQuery, 0) If nRet > 0 Then Debug.Print strQuery & "=" & Left$(strOutput, nRet) End If strQuery = "sizeofEncryptedKey" nRet = CMS_QueryEnvData(vbNullString, 0, strCmsFile, strQuery, 0) Debug.Print strQuery & "=" & nRet strCmsFile = "5.2.bin" Debug.Print "File " & strCmsFile & "..." nRet = CMS_QueryEnvData(strOutput, Len(strOutput), strCmsFile, "version", 0) Debug.Print "Version=" & nRet nRet = CMS_QueryEnvData(strOutput, Len(strOutput), strCmsFile, "contentEncryptionAlgorithm", 0) If nRet > 0 Then Debug.Print "contentEncryptionAlgorithm=" & Left$(strOutput, nRet) End If
In this example, file 5.1.bin is CMS Version 0 with content encryption algorithm des_EDE3-CBC, and
file 5.2.bin is CMSVersion 2 with content encryption algorithm rc2CBC.
File 5.1.bin... version=0 contentEncryptionAlgorithm=des-EDE3-CBC sizeofEncryptedContent=32 countOfRecipientInfos=1 keyEncryptionAlgorithm=rsaEncryption sizeofEncryptedKey=128 File 5.2.bin... Version=2 contentEncryptionAlgorithm=rc2CBC
Dim strQuery As String Dim strOutput As String Dim strEnvDataFile As String strEnvDataFile = "5.1.bin" Debug.Print "FILE: " & strEnvDataFile strQuery = "keyEncryptionAlgorithm" strOutput = cmsQueryEnvData(strEnvDataFile, strQuery, 0) Debug.Print strQuery & " ==> " & strOutput strQuery = "contentEncryptionAlgorithm" strOutput = cmsQueryEnvData(strEnvDataFile, strQuery, 0) Debug.Print strQuery & " ==> " & strOutput strQuery = "sizeofEncryptedContent" strOutput = cmsQueryEnvData(strEnvDataFile, strQuery, 0) Debug.Print strQuery & " ==> " & strOutput
Queries a CMS signed-data object file for selected information.
Public Declare Function CMS_QuerySigData Lib "diCrPKI.dll"
(ByVal strDataOut As String, ByVal nDataLen As Long,
ByVal strFileIn As String, ByVal strQuery As String, ByVal nOptions As Long) As Long
nRet = CMS_QuerySigData(strDataOut, nDataLen, strFileIn, strQuery,
nOptions) As Long
long __stdcall CMS_QuerySigData(char *szOutput, long nOutChars, const char *szFileIn, const char *szQuery, long nOptions);
If successful, the return value is a positive integer indicating either the result itself (if the result is a number) or the number of characters in the output string (if the query is looking for a string). If the item queried cannot be found, the return value is zero. If there is an error (e.g. an invalid signed-data file), it returns a negative error code.
Public Function cmsQuerySigData (szFileIn As String, szQuery As String, Optional nOptions As Long = 0) As String
static std::string dipki::Cms::QuerySigData (const std::string &inputFile, const std::string &query)
static Cms.query_sigdata(cmsfile, query)
This function queries a given SignedData file for selected information.
Only version 1 signed-data objects are fully supported.
The function will attempt to query other versions but may not succeed.
Note that this function does not verify any data, including the messageDigest attribute, it just returns what it finds.
The query string is case-insensitive, so "version", "Version" and "VeRsIoN" are all valid.
Valid queries are (case-insensitive):
| Query String | Returns | Data Type |
|---|---|---|
version | signedData version (sdVer) value | Number |
eContentType | ContentType of the EncapsulatedContentInfo, e.g. "data" | String |
HASeContent | 1 if eContent is present; 0 if not | Number |
CountOfCertificates | Number of certificates in the SignedData | Number |
CountOfSignerInfos | Number of SignerInfos in the SignedData | Number |
CountOfDigestAlgs | Number of DigestAlgorithmIdentifiers in the SignedData [New in v23.0] | Number |
certificate/N | Nth certificate encoded in base64 [New in v23.0] | String |
signerInfoVersion | signerInfo version (siVer) value | Number |
digestAlgorithm | digestAlgorithm, e.g. "sha1" | String |
signatureAlgorithm | signatureAlgorithm, e.g. "rsaEncryption" | String |
signatureValue | Signature value encoded in hex | String |
HASsignedAttributes | 1 if signedAttributes (authenticatedAttributes) are present; 0 if not | Number |
DigestOfSignedAttrs | Computed digest over signed attributes, if present, using digestAlgorithm | String |
DigestOfeContent | Computed digest over eContent, if present, using digestAlgorithm | String |
signingTime | signingTime attribute in format "2005-12-31 23:30:59" | String |
messageDigest | messageDigest attribute in hexadecimal format, if present | String |
pssParams | Parameters used for RSA-PSS (if applicable). | String |
HASsigningCertificate | 1 if an ESS signingCertificate is present; 0 if not. | Number |
signingCertHash | certHash value of ESS signing certificate, if present, encoded in hex | String |
HASalgorithmProtection | 1 if a cmsAlgorithmProtection attribute is present; 0 if not. | Number |
HASsubjectKeyIdentifier | 1 if signerIdentifier is the CHOICE subjectKeyIdentifier; 0 if issuerAndSerialNumber [New in v23.0] | Number |
signerIdentifier | signerIdentifier value encoded in hex [New in v23.0] | String |
By default, the function queries the first signerInfo in the file.
To query the Nth signerInfo append "/N" to the query string, e.g.
"signerInfoVersion/2" to find the version number of the second signerInfo in the file.
[New in v23.0] The query "certificate/N" will output the Nth certificate in the CertificateSet (default N = 1) encoded in base64.
Note that the length of an X.509 certificate is typically several hundred bytes.
The "raw" VBA/C function behaves differently depending on whether the output is a string or a number. If the result data type is a number then it returns the value directly. If the result is a string, then it sets szOutput and returns the number of characters in the string. The required number of characters can be found by passing zero for nOutChars or a null string for szOutput. ANSI C users must add one to this value when allocating memory.
Note that the VBA wrapper function and the C#/VB.NET methods always return a string, which is different from the behaviour of the raw VB6/C function.
To find out the type of data returned for a given query, use the PKI_QUERY_GETTYPE option.
The function will return either PKI_QUERY_NUMBER (1) or PKI_QUERY_STRING (2),
or a negative "invalid query" error.
For example
nRet = CMS_QuerySigData("", 0, "", "version", PKI_QUERY_GETTYPE);
will return PKI_QUERY_NUMBER.
This example queries information from various sample files.
Dim strCMSFile As String Dim nRet As Long Dim strOutput As String ' Pre-dimension output string strOutput = String(64, " ") strCMSFile = "4.6.bin" nRet = CMS_QuerySigData(strOutput, Len(strOutput), strCMSFile, "version", 0) Debug.Print "Version=" & nRet strCMSFile = "4.7.bin" nRet = CMS_QuerySigData(strOutput, Len(strOutput), strCMSFile, "version", 0) Debug.Print "Version=" & nRet nRet = CMS_QuerySigData(strOutput, Len(strOutput), strCMSFile, "signingTime", 0) If nRet > 0 Then Debug.Print "signingTime=" & Left$(strOutput, nRet) Else Debug.Print "ERROR=" & nRet End If strCMSFile = "BasicSignByAlice_attr.bin" nRet = CMS_QuerySigData(strOutput, Len(strOutput), strCMSFile, "signingTime", 0) If nRet > 0 Then Debug.Print "signingTime=" & Left$(strOutput, nRet) Else Debug.Print "ERROR=" & nRet End If
In this example, file 4.6.bin is CMS Version 1, file 4.7.bin is CMS Version 3 with no signingTime attribute (if not present, it returns error code zero), and the file BasicSignByAlice_attr.bin was signed at 7:31 a.m. on 25th February 2006:
Version=1 Version=3 ERROR=0 signingTime=2006-02-25 07:31:01
Dim strCMSFile As String Dim strQuery As String Dim strOutput As String strCMSFile = "4.6.bin" Debug.Print "FILE: " & strCMSFile strQuery = "version" strOutput = cmsQuerySigData(strCMSFile, strQuery) Debug.Print strQuery & " ==> [" & strOutput & "]" strQuery = "digestAlgorithm" strOutput = cmsQuerySigData(strCMSFile, strQuery) Debug.Print strQuery & " ==> [" & strOutput & "]" strCMSFile = "4.7.bin" Debug.Print "FILE: " & strCMSFile strQuery = "version" strOutput = cmsQuerySigData(strCMSFile, strQuery) Debug.Print strQuery & " ==> [" & strOutput & "]" strQuery = "signatureAlgorithm" strOutput = cmsQuerySigData(strCMSFile, strQuery) Debug.Print strQuery & " ==> [" & strOutput & "]" strCMSFile = "BasicSignByAlice_attr.bin" Debug.Print "FILE: " & strCMSFile strQuery = "signingTime" strOutput = cmsQuerySigData(strCMSFile, strQuery) Debug.Print strQuery & " ==> [" & strOutput & "]"
CMS_ReadSigData CMS_GetSigDataDigest
Read and extract the decompressed contents of a CMS compressed-data file.
Public Declare Function CMS_ReadComprData Lib "diCrPKI.dll" (ByVal strFileOut As String, ByVal strFileIn As String, ByVal nOptions As Long) As Long
nRet = CMS_ReadComprData(strFileOut, strFileIn, nOptions) As Long
long __stdcall CMS_ReadComprData(const char *szFileOut, const char *szFileIn, long nOptions);
If successful, the return value is the number of bytes in the output file; otherwise it returns a negative error code.
static int dipki::Cms::ReadComprData (const std::string &outputFile, const std::string &inputFile, ComprDataOptions opts=ComprDataOptions::Default_ComprDataOpt)
static Cms.read_comprdata(outputfile, inputfile, opts=ComprDataOpts.DEFAULT)
This will read and extract the contents of a CMS compressed-data file (conventionally saved with a .p7z extension)
which uses the zlibCompress algorithm.
It only works in file-to-file mode.
Any existing file with the same name as the parameter szFileOut will be overwritten without warning.
Use the PKI_CMS_NO_INFLATE option to extract the compressed data as is without inflation.
See example in CMS_MakeComprData.
Read and decrypt a CMS enveloped-data object to a file.
Public Declare Function CMS_ReadEnvData Lib "diCrPKI.dll"
(ByVal strFileOut As String, ByVal strFileIn As String,
ByVal strCertFile As String, ByVal strPrivateKey As String,
ByVal nOptions As Long) As Long
nRet = CMS_ReadEnvData(strFileOut, strFileIn,
strCertFile, strPrivateKey, nOptions) As Long
long __stdcall CMS_ReadEnvData(const char *szFileOut, const char *szFileIn, const char *szCertFile, const char *szPrivateKey, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
static int dipki::Cms::ReadEnvDataToFile (const std::string &outputFile, const std::string &inputFile, const std::string &privateKey, const std::string &certFile="", bool bigFile=false)
static Cms.read_envdata_to_file(outputfile, inputfile, prikeystr, certfile="", bigfile=False)
If received as an attachment to an S/MIME email message, the user must first extract the CMS object from the email (Hint: use a text editor and cut out the base64 data from the message - see Sending an enveloped-data object and work backwards).
The optional certificate szCertFile is used to identify the intended recipient in a message addressed to multiple recipients. If the intended recipient's certificate is not provided, the first valid message that can be decrypted using the given private key, if any, will be extracted.
The supported EnvelopedData and AuthEnvelopedData objects are those described in CMS Content Types.
Use the PKI_CMS_BIGFILE option to process large files more efficiently.
See the example in CMS_MakeEnvData().
[Changes in v12.1] To avoid certain attacks that rely on timing differences, the encrypted content will always be decrypted.
If all else is good but no valid content encryption key (CEK) can be found in the recipient data, then a random key will be used.
The end result in this latter case will always be a negative DECRYPT_ERROR with no further information as to the cause.
If there is something obviously wrong with the input, such as a badly-formed input file (INVALID_DATA_ERROR),
or the given certificate does not have a match with any recipient (NO_MATCH_ERROR),
then an appropriate error code will be returned.
The following example reads the file created with CMS_MakeEnvData above.
Bob's private key needs to be read into a string first
(see RSA_ReadEncPrivateKey).
The output is written directly to a new file.
Dim nRet As Long Dim strFileIn As String Dim strFileOut As String Dim strPrivateKey As String ' Bob reads his private key into a string strPrivateKey = rsaReadPrivateKey("BobPrivRSAEncrypt.p8e", "password") If Len(strPrivateKey) = 0 Then MsgBox "Cannot read private key" Exit Function End If ' Decrypt the input file; send plaintext to new output file strFileIn = "cmsalice2bob.p7m" strFileOut = "fromalice.txt" nRet = CMS_ReadEnvData(strFileOut, strFileIn, "", strPrivateKey, 0) Debug.Print "CMS_ReadEnvData returns " & nRet ' Clean up WIPE_String strPrivateKey, Len(strPrivateKey) strPrivateKey = ""
CMS_ReadEnvDataToString CMS_MakeEnvDataFromString CMS_MakeEnvData
Reads and decrypts CMS enveloped-data object using the recipient's private key writing the plaintext data directly into a byte array.
Public Declare Function CMS_ReadEnvDataToBytes Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByVal strFileIn As String, ByVal strCertFile As String, ByVal strPrivateKey As String, ByVal nOptions As Long) As Long
nRet = CMS_ReadEnvDataToBytes(lpOutput(0), nOutBytes, strFileIn, strCertFile, strPrivateKey, nOptions) As Long
long __stdcall CMS_ReadEnvDataToBytes(unsigned char *lpOutput, long nOutBytes, const char *szFileIn, const char *szCertFile, const char *szPrivateKey, long nOptions);
If successful, the return value is the number of bytes in the decrypted plaintext; otherwise it returns a negative error code.
Public Function cmsReadEnvDataToBytes (szFileIn As String, szCertFile As String, szPrivateKey As String, Optional nOptions As Long = 0) As Byte()
static bvec_t dipki::Cms::ReadEnvDataToBytes (const std::string &inputFile, const std::string &privateKey, const std::string &certFile="")
static Cms.read_envdata_to_bytes(inputfile, prikeystr, certfile="")
See the remarks for CMS_ReadEnvData() above.
Call the function with a NULL lpOutput or zero nOutBytes parameter to find out the required length of
the output buffer.
Alternatively, use the CMS_QueryEnvData()
function with the query "sizeofEncryptedContent".
This will return an upper bound on the length of the decrypted plaintext, at most 16 bytes too long.
Calling CMS_ReadEnvDataToString() with a properly-sized output buffer will return the exact size of the
recovered plaintext.
The buffer must be large enough to receive the entire output or a SHORT_BUF_ERROR error will result.
Use this function if the output plaintext is known to contain non-ASCII characters such as UTF-8 encoded.
The following example reads the file created with CMS_MakeEnvDataFromBytes above.
Bob's private key needs to be read into a string first
(see RSA_ReadAnyPrivateKey).
The UTF-8-encoded output is written into a byte array, then converted to a VB Unicode string.
Dim strEnvDataFile As String
Dim strData As String
Dim abData() As Byte
Dim nBytes As Long
Dim strPrivateKey As String
Dim nChars As Long
' Read encrypted content from file
strEnvDataFile = "cmsalice2bob_utf8.p7m"
' Read in Bob's encrypted private key
strPrivateKey = rsaReadPrivateKey("BobPrivRSAEncrypt.p8e", "password")
If Len(strPrivateKey) = 0 Then
MsgBox "Cannot read private key"
Exit Sub
End If
' Find required length
nBytes = CMS_ReadEnvDataToBytes(ByVal 0&, 0, strEnvDataFile, "", strPrivateKey, 0)
Debug.Print "CMS_ReadEnvDataToBytes returns " & nBytes
If nBytes <= 0 Then
MsgBox "CMS_ReadEnvDataToBytes FAILED"
GoTo CleanUp
End If
' Dimension byte array to receive data
ReDim abData(nBytes - 1)
' Extract the plaintext data
nBytes = CMS_ReadEnvDataToBytes(abData(0), nBytes, strEnvDataFile, "", strPrivateKey, 0)
Debug.Print "HEX(PT)=" & cnvHexStrFromBytes(abData)
' Convert from UTF-8 to VB Unicode string
nChars = CNV_Latin1FromUTF8Bytes(0, 0, abData(0), nBytes)
If nChars <= 0 Then
MsgBox "CNV_Latin1FromUTF8Bytes FAILED"
GoTo CleanUp
End If
strData = String(nChars, " ")
nChars = CNV_Latin1FromUTF8Bytes(strData, nChars, abData(0), nBytes)
Debug.Print "PT=" & strData
CleanUp:
wipeString strPrivateKey
CMS_ReadEnvDataToBytes returns 38 HEX(PT)=3C646F633E3C6E616D6520633D276573273EC38DC3B169676F3C2F6E616D653E3C2F646F633E PT=<doc><name c='es'>Íñigo</name></doc>
Dim strPrivateKey As String Dim lpData() As Byte Dim strData As String ' Read in private key to internal key string strPrivateKey = rsaReadPrivateKey("BobPrivRSAEncrypt.p8e", "password") Debug.Assert Len(strPrivateKey) > 0 ' 1. Decrypted content is UTF-8 encoded lpData = cmsReadEnvDataToBytes("cmsalice2bob_utf8.p7m", "", strPrivateKey, 0) Debug.Assert cnvBytesLen(lpData) > 0 Debug.Print "HEX(PT)=" & cnvHexStrFromBytes(lpData) ' Convert from UTF-8-encoded bytes to VB Unicode string strData = cnvLatin1FromUTF8Bytes(lpData) Debug.Print "PT=" & strData ' 2. Decrypted content is plain ANSI string strData = cmsReadEnvDataToString("cms2bobandcarl.p7m", "", strPrivateKey, 0) Debug.Print "PT=" & strData ' Clean up strPrivateKey = wipeString(strPrivateKey)
CMS_ReadEnvData CMS_ReadEnvDataToBytes CMS_MakeEnvDataFromString CMS_MakeEnvData CMS_QueryEnvData
Reads and decrypts CMS enveloped-data object using the recipient's private key writing the plaintext data directly into a string.
Public Declare Function CMS_ReadEnvDataToString Lib "diCrPKI.dll"
(ByVal strDataOut As String, ByVal nDataLen As Long,
ByVal strFileIn As String, ByVal strCertFile As String,
ByVal strPrivateKey As String, ByVal nOptions As Long) As Long
nRet = CMS_ReadEnvDataToString(strDataOut, nDataLen, strFileIn,
strCertFile, strPrivateKey, nOptions) As Long
long __stdcall CMS_ReadEnvDataToString(char *szOutput, long nOutChars, const char *szFileIn, const char *szCertFile, const char *szPrivateKey, long nOptions);
If successful, the return value is the number of bytes in the decrypted plaintext; otherwise it returns a negative error code.
Public Function cmsReadEnvDataToString (szFileIn As String, szCertFile As String, szPrivateKey As String, Optional nOptions As Long = 0) As String
Cms.ReadEnvDataToString Method
static Cms.read_envdata_to_string(inputfile, prikeystr, certfile="")
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
See the remarks for CMS_ReadEnvData() above.
Alternatively, use the CMS_QueryEnvData()
function with the query "sizeofEncryptedContent".
This will return an upper bound on the length of the decrypted plaintext, at most 16 bytes too long.
Calling CMS_ReadEnvDataToString() with a properly-sized output buffer will return the exact size of the
recovered plaintext.
The buffer must be large enough to receive the entire output or a SHORT_BUF_ERROR error will result.
Use this function only if the output plaintext is known to be plain ASCII text with no embedded NUL (zero) characters, otherwise use CMS_ReadEnvDataToBytes.
The following example reads the file created with CMS_MakeEnvData above.
Bob's private key needs to be read into a string first
(see RSA_ReadAnyPrivateKey).
The output is written into a string.
Dim strPrivateKey As String
Dim strFileIn As String
Dim strDataOut As String
Dim nLen As Long
Dim strCertFile As String
strFileIn = "cms2bobandcarl.p7m"
' First, Bob reads his private key into a string
strPrivateKey = rsaReadPrivateKey("BobPrivRSAEncrypt.p8e", "password")
If Len(strPrivateKey) = 0 Then
MsgBox "Cannot read private key"
Exit Sub
End If
' Query the size of encrypted content (no need for an output buffer)
nLen = CMS_QueryEnvData("", 0, strFileIn, "sizeofEncryptedContent", 0)
Debug.Print "CMS_QueryEnvData returns " & nLen
If nLen <= 0 Then
GoTo CleanUp
End If
' Pre-dimension string and read in the plaintext
' The final plaintext will always be shorter than the encrypted content.
strDataOut = String(nLen, " ")
nLen = CMS_ReadEnvDataToString(strDataOut, nLen, _
strFileIn, "", strPrivateKey, 0)
Debug.Print "CMS_ReadEnvDataToString returns " & nLen
If nLen > 0 Then
' Fix correct size for final, unpadded plaintext
strDataOut = Left(strDataOut, nLen)
Debug.Print "Plaintext is '" & strDataOut & "'"
End If
CleanUp:
WIPE_String strPrivateKey, Len(strPrivateKey)
strPrivateKey = ""
Dim strPrivateKey As String Dim lpData() As Byte Dim strData As String ' Read in private key to internal key string strPrivateKey = rsaReadPrivateKey("BobPrivRSAEncrypt.p8e", "password") Debug.Assert Len(strPrivateKey) > 0 ' 1. Decrypted content is UTF-8 encoded lpData = cmsReadEnvDataToBytes("cmsalice2bob_utf8.p7m", "", strPrivateKey, 0) Debug.Assert cnvBytesLen(lpData) > 0 Debug.Print "HEX(PT)=" & cnvHexStrFromBytes(lpData) ' Convert from UTF-8-encoded bytes to VB Unicode string strData = cnvLatin1FromUTF8Bytes(lpData) Debug.Print "PT=" & strData ' 2. Decrypted content is plain ANSI string strData = cmsReadEnvDataToString("cms2bobandcarl.p7m", "", strPrivateKey, 0) Debug.Print "PT=" & strData ' Clean up strPrivateKey = wipeString(strPrivateKey)
CMS_ReadEnvData CMS_ReadEnvDataToBytes CMS_MakeEnvDataFromString CMS_MakeEnvData CMS_QueryEnvData
Reads the content from a CMS signed-data object file.
Public Declare Function CMS_ReadSigData Lib "diCrPKI.dll"
(ByVal strFileOut As String, ByVal strFileIn As String,
ByVal nOptions As Long) As Long
nRet = CMS_ReadSigData(strFileOut, strFileIn,
nOptions) As Long
long __stdcall CMS_ReadSigData(const char *szFileOut, const char *szFileIn, long nOptions);
If successful, the return value is a positive number indicating the number of bytes in the content; otherwise it returns a negative error code.
static int dipki::Cms::ReadSigDataToFile (const std::string &outputFile, const std::string &inputFile, bool bigFile=false)
static Cms.read_sigdata_to_file(outputfile, inputfile, bigfile=False)
This function extracts the signed data from the signed-data CMS object without making any attempt to verify it. Any existing file with the same name as the specified output will be overwritten without further warning.
This function automatically checks for and reads "naked" SignedData files as per PKCS#7 version 1.6 [PKCS7-EXT] as well as the default SignedData objects properly encapsulated in an outerContentInfo as per the S/MIME standard.
This example reads the content from the signed CMS object created in the example for CMS_MakeSigData above. The output is written directly to a file and should contain the 28 bytes "This is some sample content."
Dim nRet As Long
Dim strFileIn As String
Dim strFileOut As String
strFileIn = "BasicSignByAlice.bin"
strFileOut = "BasicSignByAlice.dat"
nRet = CMS_ReadSigData(strFileOut, strFileIn, 0)
Debug.Print "CMS_ReadSigData returns " & nRet
The function should return 28 indicating the number of bytes written to the output file.
CMS_ReadSigDataToString CMS_GetSigDataDigest
Reads the content from a CMS signed-data object file directly into a byte array.
Public Declare Function CMS_ReadSigDataToBytes Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByVal strFileIn As String, ByVal nOptions As Long) As Long
nRet = CMS_ReadSigDataToBytes(lpOutput(0), nOutBytes, strFileIn, nOptions) As Long
long __stdcall CMS_ReadSigDataToBytes(unsigned char *lpOutput, long nOutBytes, const char *szFileIn, long nOptions);
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 Function cmsReadSigDataToBytes (szFileIn As String, Optional nOptions As Long = 0) As Byte()
static bvec_t dipki::Cms::ReadSigDataToBytes (const std::string &inputFile)
static Cms.read_sigdata_to_bytes(inputfile)
This function extracts the signed content from the signed-data CMS object without making any attempt to verify it.
Call the function with a NULL abOutput array or zero nOutBytes parameter to find out the required length of
the output buffer.
The buffer must be large enough to receive the entire output or a SHORT_BUF_ERROR error will result.
Use this function if the content contains non-ASCII characters such as UTF-8 encoded.
This example reads the content from the signed CMS object created in the example for
CMS_MakeSigDataFromBytes.
Dim nRet As Long Dim strSigDataFile As String Dim abData() As Byte Dim nBytes As Long strSigDataFile = "basicsignedbyalice_utf8.p7m" Debug.Print "Reading signed-data file '" & strSigDataFile & "'" ' How long is the content to be read? nBytes = CMS_ReadSigDataToBytes(ByVal 0&, 0, strSigDataFile, 0) Debug.Print "CMS_ReadSigDataToBytes returns " & nBytes If nBytes <= 0 Then Exit Function End If ' Dimension byte array to receive data ReDim abData(nBytes - 1) nBytes = CMS_ReadSigDataToBytes(abData(0), nBytes, strSigDataFile, 0) ' Display extracted content in hex Debug.Print "HEX(data)=" & cnvHexStrFromBytes(abData) & " (" & UBound(abData) + 1 & " bytes)"
This should result in the output:
Reading signed-data file 'basicsignedbyalice_utf8.p7m' CMS_ReadSigDataToBytes returns 38 HEX(data)=3C646F633E3C6E616D6520633D276573273EC38DC3B169676F3C2F6E616D653E3C2F646F633E (38 bytes)
Dim lpData() As Byte Dim strData As String ' Read UTF-8 encoded data from signed-data CMS object lpData = cmsReadSigDataToBytes("basicsignedbyalice_utf8.p7m") Debug.Assert cnvBytesLen(lpData) > 0 Debug.Print "HEX(CONTENT)=" & cnvHexStrFromBytes(lpData) ' Convert from UTF-8-encoded bytes to VB Unicode string strData = cnvLatin1FromUTF8Bytes(lpData) Debug.Print "CONTENT='" & strData & "'"
CMS_ReadSigData CMS_ReadSigDataToString CMS_GetSigDataDigest
Reads the content from a CMS signed-data object file directly into a string.
Public Declare Function CMS_ReadSigDataToString Lib "diCrPKI.dll"
(ByVal strDataOut As String, ByVal nDataLen As Long,
ByVal strFileIn As String, ByVal nOptions As Long) As Long
nRet = CMS_ReadSigDataToString(strDataOut, nDataLen, strFileIn,
nOptions) As Long
long __stdcall CMS_ReadSigDataToString(char *szOutput, long nOutChars, const char *szFileIn, long nOptions);
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 Function cmsReadSigDataToString (szFileIn As String, Optional nOptions As Long = 0) As String
Cms.ReadSigDataToString Method
static Cms.read_sigdata_to_string(inputfile)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
This function extracts the signed data from the signed-data CMS object without making any attempt to verify it.
The buffer must be large enough to receive the entire output or a SHORT_BUF_ERROR error will result.
Use this only when the signed content is known to be plain ASCII text, otherwise use CMS_ReadSigDataToBytes.
This example reads the content from the signed CMS object from example 4.2 in [SMIME-EX].
Dim nRet As Long Dim strFileIn As String Dim strData As String Dim nDataLen As Long strFileIn = "4.2.bin" ' How long is the content to be read? nDataLen = CMS_ReadSigDataToString("", 0, strFileIn, 0) If nDataLen <= 0 Then Exit Function End If ' Pre-dimension string to receive data strData = String(nDataLen, " ") nRet = CMS_ReadSigDataToString(strData, nDataLen, strFileIn, 0) Debug.Print "CMS_ReadSigDataToString returns " & nRet Debug.Print "Data is [" & strData & "]"
This should result in the output:
CMS_ReadSigDataToString returns 28 Data is [This is some sample content.]
Dim strHexDigest As String Dim strData As String Const strCMSFile As String = "4.2.bin" ' Extract the digest value strHexDigest = cmsGetSigDataDigest(strCMSFile, "") Debug.Print "extracted digest=[" & strHexDigest & "]" ' Extract content from signed-data file strData = cmsReadSigDataToString(strCMSFile) Debug.Print "content='" & strData & "'" ' Compute digest value over the content Debug.Print "computed digest =[" & hashHexFromBytes(StrConv(strData, vbFromUnicode), PKI_HASH_SHA1) & "]"
CMS_ReadSigData CMS_ReadSigDataToBytes CMS_GetSigDataDigest
Verifies the signature and content of a signed-data CMS object file.
Public Declare Function CMS_VerifySigData Lib "diCrPKI.dll"
(ByVal strFileIn As String, ByVal strCertFile As String,
ByVal strHexDigest As String, ByVal nOptions As Long) As Long
nRet = CMS_VerifySigData(strFileIn, strCertFile, strHexDigest, nOptions) As Long
long __stdcall CMS_VerifySigData(const char *szFileIn, const char *szCertFile, const char *szHexDigest, long nOptions);
"" to use the certificate(s)
in the input file.
"" to verify the eContent data in the SignedData file.
If successful, the return value is zero; otherwise it returns a negative error code.
Public Function cmsVerifySigData (szFileIn As String, Optional szCertFile As String = "", Optional szHexDigest As String = "", Optional nOptions As Long = 0) As Long
static bool dipki::Cms::VerifySigData (const std::string &inputFile, const std::string &certFile="", const std::string &hexDigest="", bool bigFile=false)
static Cms.verify_sigdata(sigdatafile, certfile="", hexdigest="", bigfile=False)
This function verifies that the content was indeed signed by the purported signer. Note that it returns zero
to indicate success, not true.
If a certificate is specified in szCertFile then the public key from that certificate will be used
and a matching signerInfo will be searched for in the SignedData file. Otherwise the first matching pair of
certificate and signerInfo found in the SignedData file will be used.
If the signed content (eContent) is included in the SignedData object (this is the usual case), then specify an empty string ("")
for szHexDigest. For a "detached-signature" file where the signed content
has been passed to the user by other means,
compute a separate message digest of the data and pass it to the function in the
szHexDigest parameter.
This function handles SignedData objects both with and without signedAttributes.
[New in v12.4]
If an ESS Signing Certificate attribute is found, then the purported signing certificate will be checked against the value of this attribute
as per ESS [RFC5035] and CAdES [CADES].
It is a SIGNATURE_ERROR (22) if these do not match.
[New in v12.4]
If an Algorithm Protection Attribute is found, then further verification checks will be made to prevent algorithm substitution attacks as per [RFC6211].
It is a SIGNATURE_ERROR (22) if these checks fail.
Dim nRet As Long
Dim strInputFile As String
strInputFile = "BasicSignByAlice.bin"
nRet = CMS_VerifySigData(strInputFile, "", "", 0)
Debug.Print "CMS_VerifySigData returns " & nRet & " (expecting 0)"
Removes non-base64 characters from a string.
Public Declare Function CNV_B64Filter Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal strInput As String, ByVal nStrLen As Long) As Long
nRet = CNV_B64Filter(strOutput, strInput, nStrLen)
long __stdcall CNV_B64Filter(char *szOutput, const char *szInput, long nStrLen);
If successful, the return value is the number of characters in the filtered string; otherwise it returns a negative error code.
Public Function cnvB64Filter (szB64 As String) As String
Specify a zero nOutChars or an empty string for szOutput to find the required length of the output string. ANSI C users must add one to this value when allocating memory.
Assumes that the output string is at least as long as the input string.
Wrapper function to return a filtered string directly:
Public Function cnvB64Filter(strB64 As String) As String
Dim strFiltered As String
Dim nDataLen As Long
strFiltered = String(Len(strB64), " ")
nDataLen = CNV_B64Filter(strFiltered, strB64, Len(strB64))
strFiltered = Left$(strFiltered, nDataLen)
cnvB64Filter = strFiltered
End Function
CNV_B64StrFromBytes CNV_BytesFromB64Str
Encodes an array of bytes into a base64-encoded string.
Public Declare Function CNV_B64StrFromBytes Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByRef lpInput As Byte, ByVal nInputLen As Long) As Long
nRet = CNV_B64StrFromBytes(strOutput, nOutChars, lpInput(0), nInputLen)
long __stdcall CNV_B64StrFromBytes(char *szOutput, long nOutChars, const unsigned char *lpInput, long nInputLen);
If successful, the return value is the number of characters in the encoded string; otherwise it returns a negative error code.
Public Function cnvB64StrFromBytes (lpData() As Byte) As String
Public Function cnvB64StrFromHexStr (szHex As String) As String
Public Function cnvB64StrFromString (szData As String) As String
Public Function cnvToBase64 (lpData() As Byte) As String
Cnv.ToBase64 Method (Byte[])
Cnv.ToBase64 Method (String)
static std::string dipki::Cnv::ToBase64 (const bvec_t &bv)
static std::string dipki::Cnv::ToBase64 (const std::string &s)
static Cnv.tobase64(data)
Specify a zero nOutChars or an empty string for szOutput to find the required length of the output string. ANSI C users must add one to this value when allocating memory.
This uses the base64 encoding scheme from [RFC4648]. Pass a zero value of nOutChars to find the required maximum possible number of characters in the output string. The final result may be smaller. C/C++ programmers should add one to the returned length value when allocating memory for szOutput.
The following wrapper function returns a base64-encoded string directly. Note the trap for a runtime error if the input byte array is empty.
Public Function cnvB64StrFromBytes(abData() As Byte) As String ' Returns base64 string encoding of bytes in abData or empty string on error Dim strB64 As String Dim nB64Len As Long Dim nDataLen As Long On Error GoTo CatchEmptyData nDataLen = UBound(abData) - LBound(abData) + 1 nB64Len = CNV_B64StrFromBytes(vbNullString, 0, abData(0), nDataLen) If nB64Len <= 0 Then Exit Function End If strB64 = String$(nB64Len, " ") nB64Len = CNV_B64StrFromBytes(strB64, nB64Len, abData(0), nDataLen) If nB64Len <= 0 Then Exit Function End If cnvB64StrFromBytes = Left$(strB64, nB64Len) CatchEmptyData: End Function
CNV_BytesFromB64Str CNV_B64Filter
Encodes an array of bytes into a base58-encoded string.
Public Declare Function CNV_Base58FromBytes Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByRef lpInput As Byte, ByVal nInputLen As Long) As Long
nRet = CNV_Base58FromBytes(strOutput, nOutChars, lpInput(0), nInputLen)
long __stdcall CNV_Base58FromBytes(char *szOutput, long nOutChars, const unsigned char *lpInput, long nInputLen);
If successful, the return value is the number of characters in the encoded string; otherwise it returns a negative error code.
Public Function cnvBase58FromBytes (lpInput() As Byte) As String
static std::string dipki::Cnv::ToBase58 (const bvec_t &bv)
static Cnv.tobase58(data)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
This uses the "Bitcoin" scheme of base58 encoding where the leading character '1' is reserved for representing an entire leading zero byte [BTC-B58].
Dim strBase58 As String Dim abData() As Byte Dim nBytes As Long Dim nChars As Long ' Create a byte array for testing abData = cnvBytesFromHexStr("00010966776006953D5567439E5E39F86A0D273BEED61967F6") nBytes = UBound(abData) + 1 Debug.Print "INPUT: " & cnvHexStrFromBytes(abData) ' Encode bytes as base58 string ' Find length of output string nChars = CNV_Base58FromBytes("", 0, abData(0), nBytes) If nChars < 0 Then Exit Sub ' ERROR ' Dimension string to receive output strBase58 = String(nChars, " ") ' Create output string nChars = CNV_Base58FromBytes(strBase58, nChars, abData(0), nBytes) Debug.Print "OUTPUT: " & strBase58
INPUT: 00010966776006953D5567439E5E39F86A0D273BEED61967F6 OUTPUT: 16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM
Dim lpData() As Byte
Dim strBase58 As String
lpData = cnvBytesFromHexStr("00010966776006953D5567439E5E39F86A0D273BEED61967F6")
strBase58 = cnvBase58FromBytes(lpData)
Debug.Print strBase58
' Decode base58 string to byte array
lpData = cnvBase58ToBytes(strBase58)
Debug.Print cnvHexStrFromBytes(lpData)
strBase58 = "DiManagement"
Debug.Print "INPUT: " & strBase58
lpData = cnvBase58ToBytes(strBase58)
Debug.Print cnvHexStrFromBytes(lpData)
Decodes a base58-encoded string into an array of bytes.
Public Declare Function CNV_Base58ToBytes Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByVal strInput As String) As Long
nRet = CNV_Base58ToBytes(lpOutput(0), nOutBytes, strInput)
long __stdcall CNV_Base58ToBytes(unsigned char *lpOutput, long nOutBytes, const char *szInput);
If successful, the return value is the number of bytes in the decoded array; otherwise it returns a negative error code.
Public Function cnvBase58ToBytes (szInput As String) As Byte()
static bvec_t dipki::Cnv::FromBase58 (const std::string &s)
static Cnv.frombase58(s)
This uses the "Bitcoin" scheme of base58 encoding where the leading character '1' is reserved for representing an entire leading zero byte [BTC-B58]. Pass a zero value for nOutBytes to find the required number of bytes in the output array.
Dim strBase58 As String Dim abData() As Byte Dim nBytes As Long ' Decode base58 string to byte array strBase58 = "16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM" Debug.Print "INPUT: " & strBase58 nBytes = CNV_Base58ToBytes(0, 0, strBase58) If nBytes < 0 Then Exit Sub ' ERROR ReDim abData(nBytes - 1) nBytes = CNV_Base58ToBytes(abData(0), nBytes, strBase58) ' Display byte array in hex Debug.Print "OUTPUT=" & cnvHexStrFromBytes(abData) ' Again (plug!) strBase58 = "DiManagement" Debug.Print "INPUT: " & strBase58 nBytes = CNV_Base58ToBytes(0, 0, strBase58) If nBytes < 0 Then Exit Sub ' ERROR ReDim abData(nBytes - 1) nBytes = CNV_Base58ToBytes(abData(0), nBytes, strBase58) ' Display byte array in hex Debug.Print "OUTPUT=" & cnvHexStrFromBytes(abData)
INPUT: 16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM OUTPUT=00010966776006953D5567439E5E39F86A0D273BEED61967F6 INPUT: DiManagement OUTPUT=11385B5358CD2B71E9
Dim lpData() As Byte
Dim strBase58 As String
lpData = cnvBytesFromHexStr("00010966776006953D5567439E5E39F86A0D273BEED61967F6")
strBase58 = cnvBase58FromBytes(lpData)
Debug.Print strBase58
' Decode base58 string to byte array
lpData = cnvBase58ToBytes(strBase58)
Debug.Print cnvHexStrFromBytes(lpData)
strBase58 = "DiManagement"
Debug.Print "INPUT: " & strBase58
lpData = cnvBase58ToBytes(strBase58)
Debug.Print cnvHexStrFromBytes(lpData)
Converts encoding of byte array between UTF-8 and Latin-1.
Public Declare Function CNV_ByteEncoding Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpInput As Byte, ByVal nBytes As Long, ByVal nOptions As Long) As Long
nLen = CNV_ByteEncoding(lpOutput(0), nOutBytes, lpInput(0), nBytes, nOptions) ' Note the "(0)" after the byte array parameters
long __stdcall CNV_ByteEncoding(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpInput, long nBytes, long nOptions);
If successful, the return value is a positive number indicating the number of bytes in the output array, or number of bytes required if nOutBytes is set to zero; otherwise it returns a negative error code.
Public Function cnvByteEncoding (lpInput() As Byte, nOptions As Long) As Byte()
Converting UTF-8 from Latin-1 assumes the input is from the 8-bit Latin-1 character set and so will always produce output that is valid UTF-8. However, for Latin-1 from UTF-8, the input must contain a valid sequence of UTF-8-encoded bytes and this must be convertible to a single-byte character set, or an error will be returned.
Dim abLatin1() As Byte Dim abUTF8() As Byte Dim nLatBytes As Long Dim nUtfBytes As Long ' Set up a byte array with the following 4 characters encoded in Latin-1 ' U+0061 LATIN SMALL LETTER A ' U+00E9 LATIN SMALL LETTER E WITH ACUTE ' U+00F1 LATIN SMALL LETTER N WITH TILDE ' U+0062 LATIN SMALL LETTER B nLatBytes = 4 ReDim abLatin1(nLatBytes - 1) ' NB required size minus 1 abLatin1(0) = Asc("a") abLatin1(1) = &HE9 abLatin1(2) = &HF1 abLatin1(3) = Asc("b") ' Display in hex format Debug.Print "Latin-1=" & cnvHexStrFromBytes(abLatin1) & " (" & nLatBytes & " bytes)" ' Convert encoding to UTF-8 ' First find new length and pre-dimension array nUtfBytes = CNV_ByteEncoding(0, 0, abLatin1(0), nLatBytes, PKI_CNV_UTF8_FROM_LATIN1) If nUtfBytes <= 0 Then Exit Sub 'ERROR ReDim abUTF8(nUtfBytes - 1) nUtfBytes = CNV_ByteEncoding(abUTF8(0), nUtfBytes, abLatin1(0), nLatBytes, PKI_CNV_UTF8_FROM_LATIN1) ' Display in hex format Debug.Print "UTF-8 =" & cnvHexStrFromBytes(abUTF8) & " (" & nUtfBytes & " bytes)"
This should result in output as follows:
Latin-1=61E9F162 (4 bytes) UTF-8 =61C3A9C3B162 (6 bytes)
Dim lpLatin1() As Byte Dim lpUTF8() As Byte ' Set up a byte array with the following 4 characters encoded in Latin-1 ' U+0061 LATIN SMALL LETTER A ' U+00E9 LATIN SMALL LETTER E WITH ACUTE ' U+00F1 LATIN SMALL LETTER N WITH TILDE ' U+0062 LATIN SMALL LETTER B lpLatin1 = cnvBytesFromHexStr("61E9F162") Debug.Print "Latin-1=" & cnvHexStrFromBytes(lpLatin1) & " (" & cnvBytesLen(lpLatin1) & " bytes)" lpUTF8 = cnvByteEncoding(lpLatin1, PKI_CNV_UTF8_FROM_LATIN1) Debug.Print "UTF-8 =" & cnvHexStrFromBytes(lpUTF8) & " (" & cnvBytesLen(lpUTF8) & " bytes)" ' And back again the other way... lpLatin1 = cnvByteEncoding(lpUTF8, PKI_CNV_LATIN1_FROM_UTF8) Debug.Print "Latin-1=" & cnvHexStrFromBytes(lpLatin1) & " (" & cnvBytesLen(lpLatin1) & " bytes)"
CNV_UTF8BytesFromLatin1 CNV_Latin1FromUTF8Bytes CNV_CheckUTF8Bytes
Decodes a base64-encoded string into an array of Bytes.
Public Declare Function CNV_BytesFromB64Str Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByVal strInput As String) As Long
nLen = CNV_BytesFromB64Str(lpOutput(0), nOutBytes, strInput)
long __stdcall CNV_BytesFromB64Str(unsigned char *lpOutput, long nOutBytes, const char *szInput);
If successful, the return value is the number of bytes in the decoded array; otherwise it returns a negative error code.
Public Function cnvBytesFromB64Str (szB64 As String) As Byte()
Public Function cnvFromBase64 (strBase64 As String) As Byte()
static bvec_t dipki::Cnv::FromBase64 (const std::string &s)
static Cnv.frombase64(s)
This uses the base64 encoding scheme from [RFC4648]. Pass a zero value for nOutBytes to find the required maximum possible number of bytes in the output array. The final array may be shorter.
@warning [Changed in v11.1] This function now returns an error if it finds an illegal character in the input string (previously any non-base64 character was just ignored). Whitespace characters (space, TAB, LF, CR, VT, FF) are still allowed and ignored but any other non-base64 characters will cause an error.
The following wrapper function will return the decoded bytes directly, with a default return value that won't cause a run-time error in the calling code.
Public Function cnvBytesFromB64Str(strB64 As String) As Byte() ' Returns byte array decoded from a base64 string Dim abData() As Byte Dim nDataLen As Long ' Set default return value that won't cause a run-time error cnvBytesFromB64Str = vbNullString nDataLen = CNV_BytesFromB64Str(0, 0, strB64) If nDataLen <= 0 Then Exit Function End If ReDim abData(nDataLen - 1) nDataLen = CNV_BytesFromB64Str(abData(0), nDataLen, strB64) If nDataLen <= 0 Then Exit Function End If ReDim Preserve abData(nDataLen - 1) cnvBytesFromB64Str = abData End Function
Old behaviour in the VBA immediate window:
? cnvHexStrFromBytes(cnvBytesFromB64Str("---BEGIN---/ty6mHZUMhA="))
04418837FB72EA61D950C840
Result is 12 bytes long. The non-base64 character '-' is ignored. The valid but probably unintended characters "BEGIN" are decoded.
New behaviour:
? cnvHexStrFromBytes(cnvBytesFromB64Str("---BEGIN---/ty6mHZUMhA="))
? PKI_ErrorCode()
8
Result is 0 bytes long. Error code 8 (INVALID_DATA_ERROR) is set.
CNV_B64StrFromBytes CNV_B64Filter
Decodes a hexadecimal-encoded string into an array of Bytes.
Public Declare Function CNV_BytesFromHexStr Lib "diCrPKI.dll"
(ByRef lpData As Byte, ByVal nDataLen As Long, ByVal strHex As String) As Long
nLen = CNV_BytesFromHexStr(lpData(0), nDataLen, strHex)
long __stdcall CNV_BytesFromHexStr(unsigned char *lpOutput, long nOutBytes, const char *szInput);
If successful, the return value is the number of bytes in the decoded array; otherwise it returns a negative error code.
Public Function cnvBytesFromHexStr (szHex As String) As Byte()
Public Function cnvFromHex (strHex As String) As Byte()
Public Function cnvStringFromHexStr (ByVal szHex As String) As String
static bvec_t dipki::Cnv::FromHex (const std::string &s)
static Cnv.fromhex(s)
Call the function with a null lpOutput array or zero nOutBytes to find the required length.
@warning [Changed in v11.1] This function now returns an error if it finds an illegal character in the input string
(previously any non-hex character was just ignored).
Whitespace characters and ASCII punctuation characters are still allowed and ignored (so "DE:AD:BE:EF" is OK)
but characters like those in the range [G-Zg-z] that are obviously non-hex will cause an error.
The following wrapper function will return the decoded bytes directly, with a default return value that won't cause a run-time error in the calling code.
Public Function cnvBytesFromHexStr(strHex As String) As Byte() ' Returns byte array decoded from a hex string Dim abData() As Byte Dim nDataLen As Long ' Set default return value that won't cause a run-time error cnvBytesFromHexStr = vbNullString nDataLen = CNV_BytesFromHexStr(0, 0, strHex) If nDataLen <= 0 Then Exit Function End If ReDim abData(nDataLen - 1) nDataLen = CNV_BytesFromHexStr(abData(0), nDataLen, strHex) If nDataLen <= 0 Then Exit Function End If ReDim Preserve abData(nDataLen - 1) cnvBytesFromHexStr = abData End Function
Old behaviour in the VBA immediate window:
? cnvHexStrFromBytes(cnvBytesFromHexStr("DEAGBEEF"))
DEABEE
Result is 3 bytes long. Invalid letter 'G' is silently ignored. Then the final odd letter 'F' is stripped.
New behaviour:
? cnvHexStrFromBytes(cnvBytesFromHexStr("DEAGBEEF"))
? PKI_ErrorCode()
8
Result is 0 bytes long. Error code 8 (INVALID_DATA_ERROR) is set.
CNV_HexStrFromBytes CNV_HexFilter
Checks if a string only contains valid UTF-8 characters.
@deprecated
Use CNV_CheckUTF8Bytes() instead.
Public Declare Function CNV_CheckUTF8 Lib "diCrPKI.dll"
(ByVal strInput As String) As Long
nLen = CNV_CheckUTF8(strInput)
long __stdcall CNV_CheckUTF8(const char *szInput);
Returns zero if the string is invalid UTF-8, or a positive number if the string is valid UTF-8.
Not applicable in .NET.
static int dipki::Cnv::CheckUTF8 (const bvec_t &bv)
Checks if a byte array contains valid UTF-8 characters.
Public Declare Function CNV_CheckUTF8Bytes Lib "diCrPKI.dll" (ByRef lpInput As Byte, ByVal nBytes As Long) As Long
nLen = CNV_CheckUTF8Bytes(lpInput(0), nBytes)
long __stdcall CNV_CheckUTF8Bytes(const unsigned char *lpInput, long nBytes);
Returns zero if the byte array contains invalid UTF-8, or a positive number if the byte array contains valid UTF-8, where the value of the number indicates the nature of the encoded characters (see Remarks below):
Public Function cnvCheckUTF8Bytes (lpInput() As Byte) As Long
Cnv.CheckUTF8 Method (Byte[])
static Cnv.utf8_check(data)
Return values:
| Returns | Value | Result |
|---|---|---|
| PKI_CHRS_NOT_UTF8 | 0 | Not valid UTF-8 |
| PKI_CHRS_ALL_ASCII | 1 | Valid UTF-8, all chars are 7-bit ASCII |
| PKI_CHRS_ANSI8 | 2 | Valid UTF-8, contains at least one multi-byte character equivalent to 8-bit ANSI |
| PKI_CHRS_MULTIBYTE | 3 | Valid 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. Strings that return
PKI_CHRS_ANSI8 (2) can be converted to Latin-1 format using the
CNV_Latin1FromUTF8Bytes() function. Strings that return
PKI_CHRS_MULTIBYTE (3) cannot be converted to Latin-1, and strings that return
PKI_CHRS_ALL_ASCII (1) are already OK because they only consist of 7-bit ASCII characters.
See the example in CNV_UTF8BytesFromLatin1.
Dim strData As String
Dim lpDataUTF8() As Byte
strData = "abcóéÍáñ"
Debug.Print "Latin-1 string='" & strData & "'"
Debug.Print " (" & Len(strData) & " characters)"
lpDataUTF8 = cnvUTF8BytesFromLatin1(strData)
Debug.Print "UTF-8=(0x)" & cnvHexStrFromBytes(lpDataUTF8)
Debug.Print " (" & cnvBytesLen(lpDataUTF8) & " bytes)"
Debug.Print "cnvCheckUTF8Bytes returns " & cnvCheckUTF8Bytes(lpDataUTF8) & " (expected 2)"
' And back to a string
Dim strLatin1 As String
strLatin1 = cnvLatin1FromUTF8Bytes(lpDataUTF8)
Debug.Print "Back to string='" & strLatin1 & "'"
CNV_CheckUTF8File CNV_Latin1FromUTF8Bytes CNV_UTF8BytesFromLatin1 CNV_ByteEncoding
Checks if a file contains valid UTF-8 characters.
Public Declare Function CNV_CheckUTF8File Lib "diCrPKI.dll" (ByVal strFileName As String) As Long
nLen = CNV_CheckUTF8File(strFileName)
long __stdcall CNV_CheckUTF8File(const char *szFileName);
Returns zero if the file contains invalid UTF-8,
or a positive number if the file contains valid UTF-8,
where the value of the number indicates the nature of the encoded characters:
see CNV_CheckUTF8Bytes() for more details.
If there is an error, like the file is missing or cannot be read,
then it returns a negative error code.
static int dipki::Cnv::CheckUTF8File (const std::string &fileName)
static Cnv.utf8_check_file(filename)
This is the same as CNV_CheckUTF8Bytes() but for a file instead of a byte array.
For more details, see CNV_CheckUTF8Bytes().
This example examines two XML files containing Spanish characters like é and ó. The first is encoded in UTF-8; the second in Latin-1 (ISO-8859-1).
Dim strFileName As String Dim nRet As Long strFileName = "test-utf8.xml" nRet = CNV_CheckUTF8File(strFileName) Debug.Print "CNV_CheckUTF8File(" & strFileName & ") returns " & nRet strFileName = "test-iso88591.xml" nRet = CNV_CheckUTF8File(strFileName) Debug.Print "CNV_CheckUTF8File(" & strFileName & ") returns " & nRet
CNV_CheckUTF8File(test-utf8.xml) returns 2 CNV_CheckUTF8File(test-iso88591.xml) returns 0
Removes non-hexadecimal characters from a string.
Public Declare Function CNV_HexFilter Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal strInput As String, ByVal nStrLen As Long) As Long
nRet = CNV_HexFilter(strOutput, strInput, nStrLen)
long __stdcall CNV_HexFilter(char *szOutput, const char *szInput, long nStrLen);
If successful, the return value is the number of characters in the filtered string; otherwise it returns a negative error code.
Public Function cnvHexFilter (szHex As String) As String
Specify a zero nOutChars or an empty string for szOutput to find the required length of the output string. ANSI C users must add one to this value when allocating memory.
Assumes that the output string is at least as long as the input string.
Wrapper function to return a filtered string directly:
Public Function cnvHexFilter(strHex As String) As String
Dim strFiltered As String
Dim nDataLen As Long
strFiltered = String(Len(strHex), " ")
nDataLen = CNV_HexFilter(strFiltered, strHex, Len(strHex))
strFiltered = Left$(strFiltered, nDataLen)
cnvHexFilter = strFiltered
End Function
CNV_HexStrFromBytes CNV_BytesFromHexStr
Encodes an array of bytes into a hexadecimal-encoded string.
Public Declare Function CNV_HexStrFromBytes Lib "diCrPKI.dll"
(ByVal strHex As String, ByVal nHexStrLen As Long,
ByRef lpData As Byte, ByVal nDataLen As Long) As Long
nRet = CNV_HexStrFromBytes(strHex, nHexStrLen, lpData(0), nDataLen)
long __stdcall CNV_HexStrFromBytes(char *szOutput, long nOutChars, const unsigned char *lpInput, long nInputLen);
If successful, the return value is the number of characters in the encoded string; otherwise it returns a negative error code.
Public Function cnvHexFromBytesMid (abData() As Byte, nOffset As Long, nBytes As Long) As String
Public Function cnvHexStrFromB64Str (szB64 As String) As String
Public Function cnvHexStrFromBytes (lpData() As Byte) As String
Public Function cnvHexStrFromString (szData As String) As String
Public Function cnvToHex (lpData() As Byte) As String
static std::string dipki::Cnv::ToHex (const bvec_t &bv)
static std::string dipki::Cnv::ToHex (const std::string &s)
static Cnv.tohex(data)
Specify a zero nOutChars or an empty string for szOutput to find the required length of the output string. ANSI C users must add one to this value when allocating memory.
The input array may contain bytes of any value.
If vbNullString or an empty string ("") is specified for szHex or zero for nHexStrLen,
the function will return
the maximum possible size of the encoded string. The final result may be smaller.
C/C++ programmers should add one to the returned length value when allocating memory.
The following wrapper function returns an encoded string directly.
Note that if abData is empty then UBound(abData) will raise a runtime error.
So we trap the error and return the default empty string.
Public Function cnvHexStrFromBytes(abData() As Byte) As String ' Returns hex string encoding of bytes in abData or empty string on error Dim strHex As String Dim nHexLen As Long Dim nDataLen As Long On Error GoTo CatchEmptyData nDataLen = UBound(abData) - LBound(abData) + 1 nHexLen = CNV_HexStrFromBytes(vbNullString, 0, abData(0), nDataLen) If nHexLen <= 0 Then Exit Function End If strHex = String$(nHexLen, " ") nHexLen = CNV_HexStrFromBytes(strHex, nHexLen, abData(0), nDataLen) If nHexLen <= 0 Then Exit Function End If cnvHexStrFromBytes = Left$(strHex, nHexLen) CatchEmptyData: End Function
CNV_BytesFromHexStr CNV_HexFilter
Converts a UTF-8 string into a Latin-1 string, if possible.
@deprecated Use CNV_Latin1FromUTF8Bytes() instead.
Public Declare Function CNV_Latin1FromUTF8 Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nOutChars As Long, ByVal strInput As String) As Long
nLen = CNV_Latin1FromUTF8(strOutput, nOutChars, strInput)
long __stdcall CNV_Latin1FromUTF8(char *szOutput, long nOutChars, const char *szInput);
If successful, the return value is a positive number indicating the number of characters in the output string, or number of characters required if nOutChars is set to zero; otherwise it returns a negative error code.
Not applicable in .NET.
Converts UTF-8 encoded array of bytes into a Latin-1 string, if possible.
Public Declare Function CNV_Latin1FromUTF8Bytes Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByRef lpInput As Byte, ByVal nBytes As Long) As Long
nLen = CNV_Latin1FromUTF8Bytes(strOutput, nOutChars, lpInput(0), nBytes)
long __stdcall CNV_Latin1FromUTF8Bytes(char *szOutput, long nOutChars, const unsigned char *lpInput, long nBytes);
If successful, the return value is a positive number indicating the number of characters (bytes) in the output string, or number of characters required if nOutChars is set to zero; otherwise it returns a negative error code.
Public Function cnvLatin1FromUTF8Bytes (lpInput() As Byte) As String
Use System.Text.Encoding.UTF8.GetString(bytes).
static std::string dipki::Cnv::Latin1FromUTF8Bytes (const bvec_t &bv)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The input must be valid UTF-8 data. Possible errors are INVALID_DATA_ERROR indicating invalid UTF-8 input and OUT_OF_RANGE_ERROR which indicates that the output would contain a character greater than 8 bits in size.
Dim strData As String
Dim lpDataUTF8() As Byte
strData = "abcóéÍáñ"
Debug.Print "Latin-1 string='" & strData & "'"
Debug.Print " (" & Len(strData) & " characters)"
lpDataUTF8 = cnvUTF8BytesFromLatin1(strData)
Debug.Print "UTF-8=(0x)" & cnvHexStrFromBytes(lpDataUTF8)
Debug.Print " (" & cnvBytesLen(lpDataUTF8) & " bytes)"
Debug.Print "cnvCheckUTF8Bytes returns " & cnvCheckUTF8Bytes(lpDataUTF8) & " (expected 2)"
' And back to a string
Dim strLatin1 As String
strLatin1 = cnvLatin1FromUTF8Bytes(lpDataUTF8)
Debug.Print "Back to string='" & strLatin1 & "'"
Dim strPrivateKey As String Dim lpData() As Byte Dim strData As String ' Read in private key to internal key string strPrivateKey = rsaReadPrivateKey("BobPrivRSAEncrypt.p8e", "password") Debug.Assert Len(strPrivateKey) > 0 ' 1. Decrypted content is UTF-8 encoded lpData = cmsReadEnvDataToBytes("cmsalice2bob_utf8.p7m", "", strPrivateKey, 0) Debug.Assert cnvBytesLen(lpData) > 0 Debug.Print "HEX(PT)=" & cnvHexStrFromBytes(lpData) ' Convert from UTF-8-encoded bytes to VB Unicode string strData = cnvLatin1FromUTF8Bytes(lpData) Debug.Print "PT=" & strData ' 2. Decrypted content is plain ANSI string strData = cmsReadEnvDataToString("cms2bobandcarl.p7m", "", strPrivateKey, 0) Debug.Print "PT=" & strData ' Clean up strPrivateKey = wipeString(strPrivateKey)
Dim lpData() As Byte Dim strData As String ' Read UTF-8 encoded data from signed-data CMS object lpData = cmsReadSigDataToBytes("basicsignedbyalice_utf8.p7m") Debug.Assert cnvBytesLen(lpData) > 0 Debug.Print "HEX(CONTENT)=" & cnvHexStrFromBytes(lpData) ' Convert from UTF-8-encoded bytes to VB Unicode string strData = cnvLatin1FromUTF8Bytes(lpData) Debug.Print "CONTENT='" & strData & "'"
CNV_UTF8BytesFromLatin1 CNV_CheckUTF8Bytes CNV_ByteEncoding
Converts the leftmost four bytes of an array to a 32-bit integer.
Public Declare Function CNV_NumFromBytes Lib "diCrPKI.dll" (ByRef lpInput As Byte, ByVal nBytes As Long, ByVal nOptions As Long) As Long
nRet = CNV_NumFromBytes(lpInput(0), nBytes, nOptions)
long __stdcall CNV_NumFromBytes(const unsigned char *lpInput, long nBytes, long nOptions);
Decoded integer value, or zero on error.
Public Function cnvNumFromBytes (lpInput() As Byte, Optional nOptions As Long = 0) As Long
static uint32_t dipki::Cnv::NumFromBytes (const bvec_t &bv, EndianNess endn=EndianNess::BigEndian)
static Cnv.num_from_bytes(data, endn=EndianNess.BIG_ENDIAN)
An array shorter than 4 bytes will be padded on the right with zeros.
Dim abData() As Byte
Dim nBytes As Long
Dim nRet As Long
abData = cnvBytesFromHexStr("DEADBEEF")
nBytes = UBound(abData) + 1
Debug.Print "INPUT: " & cnvHexStrFromBytes(abData)
' Default big-endian order
nRet = CNV_NumFromBytes(abData(0), nBytes, 0)
Debug.Print "CNV_NumFromBytes(BE)=0x" & Hex(nRet)
' Little-endian order
nRet = CNV_NumFromBytes(abData(0), nBytes, PKI_CNV_LITTLE_ENDIAN)
Debug.Print "CNV_NumFromBytes(LE)=0x" & Hex(nRet)
' Input shorter than 4 bytes is padded on the right with zeros
nRet = CNV_NumFromBytes(abData(0), 3, PKI_CNV_BIG_ENDIAN)
Debug.Print "CNV_NumFromBytes(BE)=0x" & Hex(nRet)
nRet = CNV_NumFromBytes(abData(0), 3, PKI_CNV_LITTLE_ENDIAN)
Debug.Print "CNV_NumFromBytes(LE)=0x" & Hex(nRet)
INPUT: DEADBEEF CNV_NumFromBytes(BE)=0xDEADBEEF CNV_NumFromBytes(LE)=0xEFBEADDE CNV_NumFromBytes(BE)=0xDEADBE00 CNV_NumFromBytes(LE)=0xBEADDE
Converts a 32-bit integer to an array of 4 bytes.
Public Declare Function CNV_NumToBytes Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByVal nNumber As Long, ByVal nOptions As Long) As Long
nRet = CNV_NumToBytes(lpOutput(0), nOutBytes, nNumber, nOptions)
long __stdcall CNV_NumToBytes(unsigned char *lpOutput, long nOutBytes, long nNumber, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function cnvNumToBytes (nNumber As Long, Optional nOptions As Long = 0) As Byte()
static bvec_t dipki::Cnv::NumToBytes (uint32_t n, EndianNess endn=EndianNess::BigEndian)
static Cnv.num_to_bytes(num, endn=EndianNess.BIG_ENDIAN)
The output byte array lpOutput will contain the representation of the integer in given order. A negative nNumber will be interpreted in equivalent twos-complement unsigned form.
Dim abData() As Byte
Dim nBytes As Long
Dim nNumber As Long
Dim nRet As Long
nBytes = 4
ReDim abData(nBytes - 1)
nNumber = &HDEADBEEF
Debug.Print "INPUT=0x" & Hex(nNumber) & " (" & nNumber & ")"
' Default big-endian order
nRet = CNV_NumToBytes(abData(0), nBytes, nNumber, 0)
Debug.Print "CNV_NumToBytes(BE)=" & cnvHexStrFromBytes(abData)
' Little-endian order
nRet = CNV_NumToBytes(abData(0), nBytes, nNumber, PKI_CNV_LITTLE_ENDIAN)
Debug.Print "CNV_NumToBytes(LE)=" & cnvHexStrFromBytes(abData)
INPUT=0xDEADBEEF (-559038737) CNV_NumToBytes(BE)=DEADBEEF CNV_NumToBytes(LE)=EFBEADDE
Dim lpData() As Byte
Dim nBytes As Long
Dim nNumber As Long
nNumber = &HDEADBEEF
Debug.Print "INPUT=0x" & Hex(nNumber) & " (" & nNumber & ")"
' Default big-endian order
lpData = cnvNumToBytes(nNumber)
Debug.Print "cnvNumToBytes(BE)=" & cnvHexStrFromBytes(lpData)
' Little-endian order
lpData = cnvNumToBytes(nNumber, PKI_CNV_LITTLE_ENDIAN)
Debug.Print "cnvNumToBytes(LE)=" & cnvHexStrFromBytes(lpData)
Reverses the order of a byte array.
Public Declare Function CNV_ReverseBytes Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByRef lpInput As Byte, ByVal nBytes As Long) As Long
nRet = CNV_ReverseBytes(lpOutput(0), lpInput(0), nBytes)
long __stdcall CNV_ReverseBytes(unsigned char *lpOutput, const unsigned char *lpInput, long nBytes);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function cnvReverseBytes (lpInput() As Byte) As Byte()
static bvec_t dipki::Cnv::ReverseBytes (const bvec_t &data)
static Cnv.reverse_bytes(data)
The output array lpOutput must be at least nBytes long. It may be the same variable as lpInput.
Dim abData() As Byte
Dim nBytes As Long
Dim nRet As Long
abData = cnvBytesFromHexStr("DEADBEEF01")
nBytes = UBound(abData) + 1
Debug.Print "INPUT: " & cnvHexStrFromBytes(abData)
nRet = CNV_ReverseBytes(abData(0), abData(0), nBytes)
Debug.Print "OUTPUT: " & cnvHexStrFromBytes(abData)
INPUT: DEADBEEF01 OUTPUT: 01EFBEADDE
Retrieve the Windows short path form of the specified path.
Not available in VBA/VB6 (no useful equivalent).
long __stdcall CNV_ShortPathName(char *szOut, long nOutChars, const wchar_t* szwFilePath);
Number of characters (bytes) in or required for the output string; otherwise it returns a negative error code.
static std::string dipki::Cnv::ShortPathName (const std::wstring &filePath)
static Cnv.shortpathname(pathName)
Use this function to find the ASCII equivalent file path for a path represented in "Unicode" UTF-16 wchar_t characters.
Then use this ASCII short name as an argument for an input file in any of the functions in this library that require a file name.
The file must exist. The output path is guaranteed to be in ASCII characters, and the base name and each folder name will be 8 characters or fewer. It may not give the same value on a different system. Windows only.
For the "raw" function, pass a NULL szOut or zero nOutChars to find the required output length in bytes. ANSI C users must add one to this value when allocating memory.
#include <wchar.h> long nchars; wchar_t *wfname; char *shortname; // Path name with Chinese characters wfname = L"ä½ å¥½.txt"; // Find required output length nchars = CNV_ShortPathName(NULL, 0, wfname); printf("CNV_ShortPathName returns %ld\n", nchars); assert(nchars >= 0); shortname = malloc(nchars + 1); nchars = CNV_ShortPathName(shortname, nchars, wfname); assert(nchars >= 0); // Output should be in ASCII printf("ShortPath='%s'\n", shortname); // ShortPath='FC0F~1.TXT' free(shortname);
#include <string> // Path name with Chinese characters std::wstring wfname = L"ä½ å¥½.txt"; std::string shortname = dipki::Cnv::ShortPathName(wfname); cout << "ShortPath='" << shortname << "'" << endl;
ShortPath='FC0F~1.TXT'
Note that the short path name may be different on your system.
Converts a string of 8-bit Latin-1 characters into UTF-8 format
@deprecated Use CNV_UTF8BytesFromLatin1() instead.
Public Declare Function CNV_UTF8FromLatin1 Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nOutChars As Long, ByVal strInput As String) As Long
nLen = CNV_UTF8FromLatin1(strOutput, nOutChars, strInput)
long __stdcall CNV_UTF8FromLatin1(char *szOutput, long nOutChars, const char *szInput);
If successful, the return value is a positive number indicating the number of (single-byte) characters in the output string, or number of characters required if nOutChars is set to zero; otherwise it returns a negative error code.
Not applicable in .NET.
Converts a string of 8-bit Latin-1 characters into a UTF-8 encoded array of bytes.
Public Declare Function CNV_UTF8BytesFromLatin1 Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByVal strInput As String) As Long
nLen = CNV_UTF8BytesFromLatin1(lpOutput(0), nOutBytes, strInput)
long __stdcall CNV_UTF8BytesFromLatin1(unsigned char *lpOutput, long nOutBytes, const char *szInput);
If successful, the return value is a positive number indicating the number of bytes in the output array, or number of bytes required if nOutBytes is set to zero; otherwise it returns a negative error code.
Public Function cnvUTF8BytesFromLatin1 (szInput As String) As Byte()
Use System.Text.Encoding.UTF8.GetBytes(Str).
static bvec_t dipki::Cnv::UTF8BytesFromLatin1 (const std::string &s)
Will set up to nOutBytes bytes in the output array. If nOutBytes is zero, it returns the required number of bytes.
Dim strData As String Dim abDataUTF8() As Byte Dim nRet As Long Dim nBytes As Long Dim nChars As Long Dim strNew As String ' Our original string data contains 5 non-ASCII characters strData = "abcóéÍáñ" Debug.Print "Latin-1 string='" & strData & "'" Debug.Print " (" & Len(strData) & " characters)" ' Convert directly to array of bytes in UTF-8 encoding ' Find required length first nBytes = CNV_UTF8BytesFromLatin1(0, 0, strData) If nBytes <= 0 Then Debug.Print "Failed to convert to UTF-8: " & nBytes Exit Sub End If ' Pre-dimension ReDim abDataUTF8(nBytes - 1) nBytes = CNV_UTF8BytesFromLatin1(abDataUTF8(0), nBytes, strData) ' Display in hex Debug.Print "UTF-8=(0x)" & cnvHexStrFromBytes(abDataUTF8) Debug.Print " (" & nBytes & " bytes)" ' Check if this is valid UTF-8 encoding nRet = CNV_CheckUTF8Bytes(abDataUTF8(0), nBytes) Debug.Print "CNV_CheckUTF8Bytes returns " & nRet & " (expected 2)" ' Now put back into a string nChars = CNV_Latin1FromUTF8Bytes("", 0, abDataUTF8(0), nBytes) If nChars <= 0 Then Debug.Print "Failed to convert to string: " & nChars Exit Sub End If strNew = String(nChars, " ") nChars = CNV_Latin1FromUTF8Bytes(strNew, nChars, abDataUTF8(0), nBytes) Debug.Print "New string='" & strNew & "' (" & nChars & " characters)"
This should result in the output:
Latin-1 string='abcóéÍáñ' (8 characters) UTF-8=(0x)616263C3B3C3A9C3ADC3A1C3B1 (13 bytes) CNV_CheckUTF8Bytes returns 2 (expected 2) New string='abcóéÍáñ' (8 characters)
Dim strData As String
Dim lpDataUTF8() As Byte
strData = "abcóéÍáñ"
Debug.Print "Latin-1 string='" & strData & "'"
Debug.Print " (" & Len(strData) & " characters)"
lpDataUTF8 = cnvUTF8BytesFromLatin1(strData)
Debug.Print "UTF-8=(0x)" & cnvHexStrFromBytes(lpDataUTF8)
Debug.Print " (" & cnvBytesLen(lpDataUTF8) & " bytes)"
Debug.Print "cnvCheckUTF8Bytes returns " & cnvCheckUTF8Bytes(lpDataUTF8) & " (expected 2)"
' And back to a string
Dim strLatin1 As String
strLatin1 = cnvLatin1FromUTF8Bytes(lpDataUTF8)
Debug.Print "Back to string='" & strLatin1 & "'"
Dim strData As String Dim strDigest As String ' Our original string data strData = "Estándares de Electrónica de México para mañana" ' Compute SHA-1 hash over UTF-8 encoded byte array strDigest = hashHexFromBytes(cnvUTF8BytesFromLatin1(strData), PKI_HASH_SHA1) Debug.Print "Digest=" & strDigest
CNV_Latin1FromUTF8Bytes CNV_CheckUTF8Bytes
Maps a UTF-16 (wide character) string to a UTF-8-encoded string.
No VBA/VB6 equivalent.
long __stdcall CNV_Utf8FromWide(char *szOut, long nOutChars, const wchar_t* wstr);
Number of characters (bytes) in or required for the output string; otherwise it returns a negative error code.
No .NET equivalent.
static std::string dipki::Cnv::Utf8FromWide (const std::wstring &wstr)
Use this function to convert a C/C++ string of "Unicode" UTF-16 wchar_t characters to a UTF-8-encoded string of type char.
For the "raw" ANSI function, pass a NULL szOut or zero nOutChars to find the required output length in bytes. Allocate one extra byte for the terminating null.
This function is for C/C++ programmers only. There is no VBA or .NET equivalent.
#include <wchar.h> long nchars; char *buf = NULL; wchar_t *wstr = L"áéÍñóü"; // Find required output length (12 in this case) nchars = CNV_Utf8FromWide(NULL, 0, wstr); printf("CNV_Utf8FromWide returns %ld\n", nchars); assert(nchars >= 0); buf = malloc(nchars + 1); // NB one extra byte nchars = CNV_Utf8FromWide(buf, nchars, wstr); assert(nchars >= 0); // Assumes console codepage is set to UTF-8 printf("[%s]\n", buf); free(buf);
#include <string> std::string s; std::wstring wstr; wstr = L"áéÍñóü"; s = dipki::Cnv::Utf8FromWide(wstr); cout << "Cnv::Utf8FromWide=[" << s << "]" << endl; cout << "s-->utf-8 bytes: " << dipki::Cnv::ToHex(dipki::str2bvec(s)) << endl;
Cnv::Utf8FromWide=[áéÍñóü] s-->utf-8 bytes: C3A1C3A9C3ADC3B1C3B3C3BC
Compress data using zlib compression.
Public Declare Function COMPR_Compress Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpInput As Byte, ByVal nInputLen As Long, ByVal nOptions As Long) As Long
nRet = COMPR_Compress(lpOutput(0), nOutputLen, lpInput(0), nInputLen, 0) ' Note the "(0)" after the byte array parameters
long __stdcall COMPR_Compress(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpInput, long nInputLen, long nOptions);
The number of bytes successfully copied into the output buffer or the required size in bytes. If an error occurs, it returns a negative error code.
Public Function comprCompress (lpInput() As Byte, Optional nOptions As Long = 0) As Byte()
static bvec_t dipki::Compr::Compress (const bvec_t &data)
static Compr.compress(data)
To determine the required size of the output buffer, call the function with nOutBytes set to zero (or lpOutput set to NULL).
Dim strPlain As String Dim strBack As String Dim abPlain() As Byte Dim abCompressed() As Byte Dim nCompLen As Long Dim nUncompLen As Long Dim nRet As Long ' COMPRESSSION (deflation) ' Set the plaintext message strPlain = "hello, hello, hello. This is a 'hello world' message " & _ "for the world, repeat, for the world." ' Convert to an array of bytes abPlain = StrConv(strPlain, vbFromUnicode) nUncompLen = UBound(abPlain) + 1 ' Find required compressed length by calling with zero length value nCompLen = COMPR_Compress(0, 0, abPlain(0), nUncompLen, 0) ReDim abCompressed(nCompLen - 1) ' Now compress plaintext Call COMPR_Compress(abCompressed(0), nCompLen, abPlain(0), nUncompLen, 0) Debug.Print "Compressed " & nUncompLen & " bytes to " & nCompLen ' DECOMPRESSSION (inflation) ' Uncompress the compressed data ' Find the required length of uncompressed data nUncompLen = COMPR_Uncompress(0, 0, abCompressed(0), nCompLen, 0) Debug.Print "Required uncompressed length is " & nUncompLen & " bytes" ReDim abPlain(nUncompLen - 1) nRet = COMPR_Uncompress(abPlain(0), nUncompLen, abCompressed(0), nCompLen, 0) ' Convert back to a string strBack = StrConv(abPlain, vbUnicode) Debug.Print strBack
Compressed 90 bytes to 68 Required uncompressed length is 90 bytes hello, hello, hello. This is a 'hello world' message for the world, repeat, for the world.
Dim strPlain As String Dim lpToCompress() As Byte Dim lpCompressed() As Byte Dim lpUncompressed() As Byte strPlain = "hello, hello, hello. This is a 'hello world' message " & _ "for the world, repeat, for the world." lpToCompress = StrConv(strPlain, vbFromUnicode) lpCompressed = comprCompress(lpToCompress) Debug.Print "OK= " & "789CCB48CDC9C9D751C840A2F4144232328B15802851411D2CA2509E5F9493A2AE909B5A5C9C989EAA90965FA45092910A11D651284A2D484D2CD14115D6030086D11F4E" Debug.Print "COMPRESSED=" & cnvHexStrFromBytes(lpCompressed) lpUncompressed = comprUncompress(lpCompressed) Debug.Print "'" & StrConv(lpUncompressed, vbUnicode); "'"
Uncompress data using zlib compression.
Public Declare Function COMPR_Uncompress Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpInput As Byte, ByVal nInputLen As Long, ByVal nOptions As Long) As Long
nRet = COMPR_Uncompress(lpOutput(0), nOutputLen, lpInput(0), nInputLen, 0) ' Note the "(0)" after the byte array parameters
long __stdcall COMPR_Uncompress(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpInput, long nInputLen, long nOptions);
The number of bytes successfully copied into the output buffer or the required size in bytes. If an error occurs, it returns a negative error code.
Public Function comprUncompress (lpInput() As Byte, Optional nOptions As Long = 0) As Byte()
static bvec_t dipki::Compr::Uncompress (const bvec_t &data)
static Compr.uncompress(data)
To determine the required size of the output buffer, call the function with nOutBytes set to zero (or lpOutput set to NULL).
See COMPR_Compress.
Dim strPlain As String Dim lpToCompress() As Byte Dim lpCompressed() As Byte Dim lpUncompressed() As Byte strPlain = "hello, hello, hello. This is a 'hello world' message " & _ "for the world, repeat, for the world." lpToCompress = StrConv(strPlain, vbFromUnicode) lpCompressed = comprCompress(lpToCompress) Debug.Print "OK= " & "789CCB48CDC9C9D751C840A2F4144232328B15802851411D2CA2509E5F9493A2AE909B5A5C9C989EAA90965FA45092910A11D651284A2D484D2CD14115D6030086D11F4E" Debug.Print "COMPRESSED=" & cnvHexStrFromBytes(lpCompressed) lpUncompressed = comprUncompress(lpCompressed) Debug.Print "'" & StrConv(lpUncompressed, vbUnicode); "'"
Compute EC Diffie-Hellman (ECDH) shared secret.
Public Declare Function ECC_DHSharedSecret Lib "diCrPKI.dll" (ByRef lpZZ As Byte, ByVal nOutBytes As Long, ByVal strIntPrivateKey As String, ByVal strIntPublicKey As String, ByVal nOptions As Long) As Long
nRet = ECC_DHSharedSecret(lpZZ(0), nOutBytes, strIntPrivateKey, strIntPublicKey, nOptions)
long __stdcall ECC_DHSharedSecret(unsigned char *lpZZ, long nOutBytes, const char *szIntPrivateKey, const char *szIntPublicKey, long nOptions);
If successful, the return value is the number of bytes in or required in the output; otherwise it returns a negative error code.
Public Function eccDHSharedSecret (szIntPrivateKey As String, szIntPublicKey As String, Optional nOptions As Long = 0) As Byte()
static bvec_t dipki::Ecc::DHSharedSecret (std::string ourIntPrivateKey, std::string theirIntPublicKey)
static Ecc.dh_shared_secret(intprikeystr, intpubkeystr)
The output is the Diffie-Hellman shared secret. This may require further processing to be used in an application; for example, as input to a key derivation function.
The keys are expected in ephemeral "internal" format read into a string using
ECC_ReadPrivateKey,
ECC_ReadPublicKey or
ECC_ReadKeyByCurve.
All supported NIST/SEC curves can be used as well as the safe curve X25519 (but not Ed25519 or Ed448, which are for signatures only).
Dim strOurPriKeyHex As String Dim strTheirPubKeyHex As String Dim strOurPrivateKey As String Dim strTheirPublicKey As String Dim strCurveName As String Dim strCorrectHex As String Dim lpZZ() As Byte Dim nChars As Long Dim nBytes As Long Dim nBits As Long ' Ref: CAVS 14.1 ECC CDH Primitive (SP800 - 56A Section 5.7.1.2) ' Test Information for "testecccdh" ecccdhtestvectors.zip '[P-256] strCurveName = "P-256" ' Our private key is dUIT: strOurPriKeyHex = "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534" ' Their public key as hex is "04" || QCAVSx || QCAVSy strTheirPubKeyHex = "04" & "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287" _ + "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac" ' Correct result is ZIUT strCorrectHex = "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b" Debug.Print "Test for curve " & strCurveName & " ..." ' Read in keys to internal key strings ' Our private key... nChars = ECC_ReadKeyByCurve("", 0, strOurPriKeyHex, strCurveName, 0) Debug.Assert nChars > 0 strOurPrivateKey = String(nChars, " ") nChars = ECC_ReadKeyByCurve(strOurPrivateKey, nChars, strOurPriKeyHex, strCurveName, 0) Debug.Assert nChars > 0 ' Check the key we read in nBits = ECC_QueryKey("", 0, strOurPrivateKey, "keyBits", 0) Debug.Print "Our private key has " & nBits & " bits" ' Their public key... nChars = ECC_ReadKeyByCurve("", 0, strTheirPubKeyHex, strCurveName, 0) Debug.Assert nChars > 0 strTheirPublicKey = String(nChars, " ") nChars = ECC_ReadKeyByCurve(strTheirPublicKey, nChars, strTheirPubKeyHex, strCurveName, 0) Debug.Assert nChars > 0 ' Check the key we read in nBits = ECC_QueryKey("", 0, strTheirPublicKey, "keyBits", 0) Debug.Print "Their public key has " & nBits & " bits" ' Compute shared secret ' - find required length nBytes = ECC_DHSharedSecret(ByVal 0&, 0, strOurPrivateKey, strTheirPublicKey, 0) Debug.Print "ECC_DHSharedSecret returns " & nBytes & " (expecting +ve)" Debug.Assert nBytes > 0 ' - allocate memory ReDim lpZZ(nBytes - 1) ' - do the business nBytes = ECC_DHSharedSecret(lpZZ(0), nBytes, strOurPrivateKey, strTheirPublicKey, 0) Debug.Assert nBytes > 0 Debug.Print "ZZ=" & cnvHexStrFromBytes(lpZZ) ' Check the result Debug.Print "OK=" & strCorrectHex Debug.Assert UCase(cnvHexStrFromBytes(lpZZ)) = UCase(strCorrectHex)
Test for curve P-256 ... Our private key has 256 bits Their public key has 256 bits ECC_DHSharedSecret returns 32 (expecting +ve) ZZ=46FC62106420FF012E54A434FBDD2D25CCC5852060561E68040DD7778997BD7B OK=46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b
Dim strCurveName As String Dim ourPrivateKey As String Dim theirPublicKey As String Dim lpZZ() As Byte ' Ref: RFC7748 Section 6.1 Const alicePrivateKeyHex As String = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" Const alicePublicKeyHex As String = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a" Const bobPrivateKeyHex As String = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb" Const bobPublicKeyHex As String = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f" strCurveName = "X25519" ' 1. Alice's private + Bob's public ourPrivateKey = eccReadKeyByCurve(alicePrivateKeyHex, strCurveName, PKI_ECC_PRIVATE_KEY) Debug.Print "Our key has " & eccQueryKey(ourPrivateKey, "keyBits") & " bits and is a " & _ IIf(eccQueryKey(ourPrivateKey, "isPrivate") = "1", "Private", "Public") & " key" theirPublicKey = eccReadKeyByCurve(bobPublicKeyHex, strCurveName, PKI_ECC_PUBLIC_KEY) Debug.Print "Their key has " & eccQueryKey(theirPublicKey, "keyBits") & " bits and is a " & _ IIf(eccQueryKey(theirPublicKey, "isPrivate") = "1", "Private", "Public") & " key" ' Compute shared secret lpZZ = eccDHSharedSecret(ourPrivateKey, theirPublicKey) Debug.Print "ZZ=" & cnvHexStrFromBytes(lpZZ) Debug.Print "OK=4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" ' 2. Bob's private + Alice's public ourPrivateKey = eccReadKeyByCurve(bobPrivateKeyHex, strCurveName, PKI_ECC_PRIVATE_KEY) Debug.Print "Our key has " & eccQueryKey(ourPrivateKey, "keyBits") & " bits and is a " & _ IIf(eccQueryKey(ourPrivateKey, "isPrivate") = "1", "Private", "Public") & " key" theirPublicKey = eccReadKeyByCurve(alicePublicKeyHex, strCurveName, PKI_ECC_PUBLIC_KEY) Debug.Print "Their key has " & eccQueryKey(theirPublicKey, "keyBits") & " bits and is a " & _ IIf(eccQueryKey(theirPublicKey, "isPrivate") = "1", "Private", "Public") & " key" ' Compute shared secret lpZZ = eccDHSharedSecret(ourPrivateKey, theirPublicKey) Debug.Print "ZZ=" & cnvHexStrFromBytes(lpZZ) Debug.Print "OK=4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
Computes the hash code of an "internal" ECC public or private key string.
Public Declare Function ECC_KeyHashCode Lib "diCrPKI.dll"
(ByVal strKeyString As String) As Long
nRet = ECC_KeyHashCode(strKeyString)
long __stdcall ECC_KeyHashCode(const char *szKeyString);
A 32-bit hash code for the key, or zero on error.
Public Function eccKeyHashCode (szIntKeyString As String) As Long
static uint32_t dipki::Ecc::KeyHashCode (std::string intKeyString)
static Ecc.key_hashcode(intkeystr)
Use this function to compare internal key strings.
The hash code value will be the same for a given key.
The hash code is computed to an internal algorithm and may return any integer value
between -2,147,483,648 and 2,147,483,647.
If the key string is invalid, the return value is zero and a nonzero error code will be set (use PKI_ErrorCode to check).
There is a very small chance (one in 4 billion) that a valid key string returns a hash code of zero.
Dim nRet As Long Dim nChars As Long Dim strPubKeyFile As String Dim strPriKeyFile As String Dim strIntKey As String Dim strPassword As String strPubKeyFile = "CA_ECC_P256.pub" strPriKeyFile = "CA_ECC_P256.p8e" strPassword = "password" ' 1. Read in private key to internal key string Debug.Print "FILE: " & strPriKeyFile ' Find required length of internal key string nChars = ECC_ReadPrivateKey("", 0, strPriKeyFile, strPassword, 0) Debug.Print "ECC_ReadPrivateKey returns " & nChars & " (expected +ve)" ' Dimension the string to receive output strIntKey = String(nChars, " ") ' Read it in nChars = ECC_ReadPrivateKey(strIntKey, Len(strIntKey), strPriKeyFile, strPassword, 0) ' Note: internal key string is only valid for the current session ' But the Key Hash Code is always the same nRet = ECC_KeyHashCode(strIntKey) Debug.Print "KeyHashCodePrivate=0x" & Hex(nRet) ' 2. Read in public key to internal string Debug.Print "FILE: " & strPubKeyFile ' Find required length of internal key string nChars = ECC_ReadPublicKey("", 0, strPubKeyFile, 0) Debug.Print "ECC_ReadPublicKey returns " & nChars & " (expected +ve)" ' Dimension the string to receive output strIntKey = String(nChars, " ") ' Read it in nChars = ECC_ReadPublicKey(strIntKey, Len(strIntKey), strPubKeyFile, 0) ' The public and private Key Hash Codes should match nRet = ECC_KeyHashCode(strIntKey) Debug.Print "KeyHashCodePublic=0x" & Hex(nRet)
FILE: CA_ECC_P256.p8e ECC_ReadPrivateKey returns 100 (expected +ve) KeyHashCodePrivate=0x37210904 FILE: CA_ECC_P256.pub ECC_ReadPublicKey returns 124 (expected +ve) KeyHashCodePublic=0x37210904
Generates an EC public/private key pair and saves as two key files.
Public Declare Function ECC_MakeKeys Lib "diCrPKI.dll" (ByVal strPubKeyFile As String, ByVal strPriKeyFile As String, ByVal strCurveName As String, ByVal strPassword As String, ByVal strParams As String, ByVal nOptions As Long) As Long
nRet = ECC_MakeKeys(strPublicKeyFile, strPrivateKeyFile, strCurveName, strPassword, strParams, nOptions)
long __stdcall ECC_MakeKeys(const char *szPubKeyFile, const char *szPriKeyFile, const char *szCurveName, const char *szPassword, const char *szParams, long nOptions);
"" for defaults.
Otherwise include a set of attribute-value pairs separated by a semi-colon ";" to set options from the following
count=<nnn> to set the iteration count in the encrypted private key used in the PBKDF method,
e.g. "count=5000;" [default=2048]
prf=<hmac-name> to change the HMAC algorithm used in the PBKDF2 method,
e.g. "prf=hmacWithSHA256;" [default=hmacwithSHA1]
rngseed=<string> to add some extra user-specified additional seed for the random number generator,
e.g. "rngseed=pqrrr1234xyz;"
{hmacWithSHA1|hmacWithSHA224|hmacWithSHA256|hmacWithSHA384|hmacWithSHA512}.
"pbeWithSHAAnd3-KeyTripleDES-CBC" (default)des-EDE3-CBCaes128-CBCaes192-CBCaes256-CBCIf successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function eccMakeKeys (szPubKeyFile As String, szPriKeyFile As String, szCurveName As String, szPassword As String, Optional szParams As String = "", Optional nOptions As Long = 0) As Long
static int dipki::Ecc::MakeKeys (const std::string &publicKeyFile, const std::string &privateKeyFile, Curve curve, const std::string &password, PbeScheme pbes=PbeScheme::Default, const std::string ¶mString="", Format fileFormat=Format::Binary)
static Ecc.make_keys(pubkeyfile, prikeyfile, curvename, password, pbescheme=0, params='', fileformat=0)
The public and private keys are encoded into ASN.1 values of type
SubjectPublicKeyInfo and EncryptedPrivateKeyInfo respectively.
Any existing files of the same names will be overwritten without warning.
The password should be a string of non-zero ASCII characters.
The key is stored by default as a pair of DER-encoded binary files. Use the PKI_KEY_FORMAT_PEM flag to save in PEM-encoded format.
Supported curve names for szCurveName are:
| Curve name | Alternative names | Remarks |
|---|---|---|
secp192r1 | P-192, P_192, prime192v1 | NIST |
secp256r1 | P-256, P_256, prime256v1 | NIST |
secp224r1 | P-224, P_224 | NIST |
secp384r1 | P-384, P_384 | NIST |
secp521r1 | P-521, P_521 | NIST |
secp256k1 | Bitcoin/SEC | |
Ed25519 | For EdDSA signatures | |
X25519 | For ECDH key exchange | |
Ed448 | For EdDSA signatures | |
X448 | For ECDH key exchange | |
brainpoolP256r1 | [RFC5639] | |
brainpoolP384r1 | [RFC5639] | |
brainpoolP512r1 | [RFC5639] |
Valid values for the "prf" parameter in szParams are:
hmacWithSHA1 (default)hmacWithSHA224hmacWithSHA256hmacWithSHA384hmacWithSHA512
Set szParams as the empty string "" for defaults.
The following example creates two new key pairs for the NIST curves P-256 and P-521, respectively.
The first example saves the private key using default options (pbeWithSHAAnd3-KeyTripleDES-CBC with an iteration count of 2048).
The second example saves the private key using PBKDF2 with AES-256 as the encryption scheme, hmacWithSHA512 as the PRF algorithm, and an iteration count of 5000.
Dim nRet As Long Dim strPublicKeyFile As String Dim strPrivateKeyFile As String Dim strPassword As String Dim strCurve As String Dim nChars As Long Dim strTypeName As String Dim strFileName As String strPublicKeyFile = "myeckeyp256.pub" strPrivateKeyFile = "myeckeyp256.p8" strPassword = "password" strCurve = "P-256" ' Create a new pair of ECC keys saved as DER-encoded files nRet = ECC_MakeKeys(strPublicKeyFile, strPrivateKeyFile, strCurve, strPassword, "", 0) Debug.Print "ECC_MakeKeys returns " & nRet & " (expected 0)" strPublicKeyFile = "myeckeyp521.pub" strPrivateKeyFile = "myeckeyp521.p8" strPassword = "password" strCurve = "P-521" ' Create a new pair of ECC keys saved as DER-encoded files nRet = ECC_MakeKeys(strPublicKeyFile, strPrivateKeyFile, strCurve, strPassword, "count=5000;prf=hmacWithSHA512;", PKI_PBE_PBKDF2_AES256) Debug.Print "ECC_MakeKeys returns " & nRet & " (expected 0)" ' Check the types of files we made strTypeName = String(PKI_ASN1_TYPE_MAXCHARS, " ") strFileName = strPublicKeyFile nChars = ASN1_Type(strTypeName, Len(strTypeName), strFileName, 0) If nChars > 0 Then Debug.Print strFileName & ": " & Left(strTypeName, nChars) strFileName = strPrivateKeyFile nChars = ASN1_Type(strTypeName, Len(strTypeName), strFileName, 0) If nChars > 0 Then Debug.Print strFileName & ": " & Left(strTypeName, nChars)
ECC_MakeKeys returns 0 (expected 0) ECC_MakeKeys returns 0 (expected 0) myeckeyp521.pub: PUBLIC KEY INFO myeckeyp521.p8: PKCS8 ENCRYPTED PRIVATE KEY
Converts an internal EC private key string into an internal EC public key string.
Public Declare Function ECC_PublicKeyFromPrivate Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strIntKeyString As String, ByVal nOptions As Long) As Long
nRet = ECC_PublicKeyFromPrivate(strOutput, nOutChars, strIntKeyString, nOptions)
long __stdcall ECC_PublicKeyFromPrivate(char *szOutput, long nOutChars, const char *szIntKeyString, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a nonzero error code.
Public Function eccPublicKeyFromPrivate (szIntKeyString As String, Optional nOptions As Long = 0) As String
Ecc.PublicKeyFromPrivate Method
static std::string dipki::Ecc::PublicKeyFromPrivate (std::string internalKey)
static Ecc.publickey_from_private(intkeystr)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
Use this to derive the public key from the EC private key, where both values are represented as "internal" key strings.
Dim nRet As Long Dim nChars As Long Dim strIntPriKey As String Dim strIntPubKey As String Dim strKeyFile As String Dim strNewKeyFile As String Dim strPassword As String Dim strTypeName As String Dim strFileName As String strKeyFile = "myeckeyp521.p8" strPassword = "password" ' 1. READ IN THE PRIVATE KEY: int_string <- file Debug.Print "FILE: " & strKeyFile ' Find required length of internal key string nChars = ECC_ReadPrivateKey("", 0, strKeyFile, strPassword, 0) Debug.Print "ECC_ReadPrivateKey returns " & nChars & " (expected +ve)" If (nChars <= 0) Then Exit Sub ' CATCH ERROR HERE ' Dimension the string to receive output strIntPriKey = String(nChars, " ") ' Read into internal key string nChars = ECC_ReadPrivateKey(strIntPriKey, Len(strIntPriKey), strKeyFile, strPassword, 0) Debug.Print "[" & strIntPriKey & "]" ' 2. CONVERT TO PUBLIC: int_string <-- int_string nChars = ECC_PublicKeyFromPrivate("", 0, strIntPriKey, 0) Debug.Print "ECC_PublicKeyFromPrivate returns " & nChars & " (expected +ve)" If (nChars <= 0) Then Exit Sub ' CATCH ERROR HERE strIntPubKey = String(nChars, " ") nChars = ECC_PublicKeyFromPrivate(strIntPubKey, Len(strIntPubKey), strIntPriKey, 0) Debug.Print "[" & strIntPubKey & "]" ' 3. SAVE AS NEW PUBLIC KEY FILE: file <-- int_string strNewKeyFile = "myeckeyp521_new.pub" nRet = ECC_SaveKey(strNewKeyFile, strIntPubKey, 0) Debug.Print "ECC_SaveKey returns " & nRet & " (expected 0)" ' Check the type of file we made strTypeName = String(PKI_ASN1_TYPE_MAXCHARS, " ") strFileName = strNewKeyFile nChars = ASN1_Type(strTypeName, Len(strTypeName), strFileName, 0) If nChars > 0 Then Debug.Print strFileName & ": " & Left(strTypeName, nChars)
FILE: myeckeyp521.p8 ECC_ReadPrivateKey returns 336 (expected +ve) [PVECRDe...PmEAIGm5Uj1HI=] ECC_PublicKeyFromPrivate returns 212 (expected +ve) [MIGbMBA...sxHXznms=] ECC_SaveKey returns 0 (expected 0) myeckeyp521_new.pub: PUBLIC KEY INFO
Dim strIntKey As String ' Read in public key from file strIntKey = eccReadPublicKey("myeckeyp256.pub") Debug.Assert Len(strIntKey) > 0 Debug.Print "Key curve=" & eccQueryKey(strIntKey, "curveName", 0) & " keyBits=" & _ eccQueryKey(strIntKey, "keyBits", 0) & _ " and is a " & _ IIf(eccQueryKey(strIntKey, "isPrivate") = "1", "Private", "Public") & " key" Debug.Print eccQueryKey(strIntKey, "publicKey") Debug.Print "KeyHashCode=0x" & Hex(ECC_KeyHashCode(strIntKey)) ' Read in private key from file strIntKey = eccReadPrivateKey("myeckeyp256.p8", "password") Debug.Assert Len(strIntKey) > 0 Debug.Print "Key curve=" & eccQueryKey(strIntKey, "curveName", 0) & " keyBits=" & _ eccQueryKey(strIntKey, "keyBits", 0) & _ " and is a " & _ IIf(eccQueryKey(strIntKey, "isPrivate") = "1", "Private", "Public") & " key" Debug.Print eccQueryKey(strIntKey, "publicKey") Debug.Print "KeyHashCode=0x" & Hex(ECC_KeyHashCode(strIntKey)) ' Derive public key from private key strIntKey = eccPublicKeyFromPrivate(strIntKey) Debug.Assert Len(strIntKey) > 0 Debug.Print "Key curve=" & eccQueryKey(strIntKey, "curveName", 0) & " keyBits=" & _ eccQueryKey(strIntKey, "keyBits", 0) & _ " and is a " & _ IIf(eccQueryKey(strIntKey, "isPrivate") = "1", "Private", "Public") & " key" Debug.Print eccQueryKey(strIntKey, "publicKey") Debug.Print "KeyHashCode=0x" & Hex(ECC_KeyHashCode(strIntKey))
ECC_ReadPrivateKey ECC_ReadPublicKey
Queries an EC key string for selected information.
Public Declare Function ECC_QueryKey Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strIntKeyString As String, ByVal strQuery As String, ByVal nOptions As Long) As Long
nRet = ECC_QueryKey(strOutput, Len(strOutput), strIntKeyString, strQuery, nOptions)
long __stdcall ECC_QueryKey(char *szOutput, long nOutChars, const char *szIntKeyString, const char *szQuery, long nOptions);
If successful, the return value is a positive integer indicating either the result itself (if the result is a number) or the number of characters in the output string (if the query is looking for a string). If the item queried cannot be found, the return value is zero. If there is an error (e.g. invalid input), it returns a negative error code.
Public Function eccQueryKey (szIntKeyString As String, szQuery As String, Optional nOptions As Long = 0) As String
static std::string dipki::Ecc::QueryKey (std::string internalKey, std::string query)
static Ecc.query_key(intkeystr, query)
Valid queries are (case-insensitive):
| Query String | Returns | Data Type |
|---|---|---|
curveName | Name of the curve | String |
keyBits | Number of bits in the key | Number |
isPrivate | 1 if the key is a private key; 0 if not | Number |
isValid | 1 if the key is valid; 0 if not | Number |
privateKey | Value of the private key in hex format | String |
publicKey | Value of the public key in hex format | String |
The "raw" VBA/C function behaves differently depending on whether the output is a string or a number. If the result data type is a number then it returns the value directly. If the result is a string, then it sets szOutput and returns the number of characters in the string. The required number of characters can be found by passing zero for nOutChars or a null string for szOutput. ANSI C users must add one to this value when allocating memory.
Note that the VBA wrapper function and the C#/VB.NET methods always return a string, which is different from the behaviour of the raw VB6/C function.
Dim nRet As Long Dim nChars As Long Dim strIntKey As String Dim strKeyFile As String Dim strQuery As String Dim strBuffer As String Dim strPassword As String strKeyFile = "myeckeyp256.p8" strPassword = "password" Debug.Print "FILE: " & strKeyFile ' Find required length of internal key string nChars = ECC_ReadPrivateKey("", 0, strKeyFile, strPassword, 0) Debug.Print "ECC_ReadPrivateKey returns " & nChars & " (expected +ve)" ' Dimension the string to receive output strIntKey = String(nChars, " ") ' Read into an ephemeral internal key string nChars = ECC_ReadPrivateKey(strIntKey, Len(strIntKey), strKeyFile, strPassword, 0) ' Find the curve name (output as a string) strBuffer = String(32, " ") strQuery = "curveName" nChars = ECC_QueryKey(strBuffer, Len(strBuffer), strIntKey, strQuery, 0) If nChars > 0 Then Debug.Print "ECC_QueryKey('" & strQuery & "')=[" & Left(strBuffer, nChars) & "]" ' Find the key size in bits (NB returned directly) strQuery = "keyBits" nRet = ECC_QueryKey("", 0, strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" & nRet & " (expected +ve)" ' Is it a private or public key? strQuery = "isPrivate" nRet = ECC_QueryKey("", 0, strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" & nRet & " (expected 1 = True)" ' Extract the private key in hex form strQuery = "privateKey" ' Get required length of output string nChars = ECC_QueryKey("", 0, strIntKey, strQuery, 0) strBuffer = String(nChars, " ") nChars = ECC_QueryKey(strBuffer, Len(strBuffer), strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" If nChars > 0 Then Debug.Print "[" & Left(strBuffer, nChars) & "]" ' Extract the public key in hex form strQuery = "publicKey" nChars = ECC_QueryKey("", 0, strIntKey, strQuery, 0) strBuffer = String(nChars, " ") nChars = ECC_QueryKey(strBuffer, Len(strBuffer), strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" If nChars > 0 Then Debug.Print "[" & Left(strBuffer, nChars) & "]"
FILE: myeckeyp256.p8
ECC_ReadPrivateKey returns 100 (expected +ve)
ECC_QueryKey('curveName')=[secp256r1]
ECC_QueryKey('keyBits')=256 (expected +ve)
ECC_QueryKey('isPrivate')=1 (expected 1 = True)
ECC_QueryKey('privateKey')=
[0955cc9904330205fa00559dbcae5c978c42a2f96fc1d661b66f617331ef0738]
ECC_QueryKey('publicKey')=
[0403af975e940d6db5184576a81fe50914579c7d777bfc70725b24505e03e49a9e004025069f3e8981d45027c953d57818a2b212ec7d1bfcfac0ea645dff81ed6b]
Dim curveName As String Dim alicePrivateKeyHex As String Dim ourPrivateKey As String curveName = "X25519" alicePrivateKeyHex = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" ourPrivateKey = eccReadKeyByCurve(alicePrivateKeyHex, curveName, PKI_ECC_PRIVATE_KEY) Debug.Assert Len(ourPrivateKey) > 0 Debug.Print "Key curve=" & eccQueryKey(ourPrivateKey, "curveName", 0) & " keyBits=" & eccQueryKey(ourPrivateKey, "keyBits", 0)
ECC_ReadPrivateKey ECC_ReadPublicKey
Reads an EC key from its hexadecimal (base16) representation.
Public Declare Function ECC_ReadKeyByCurve Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strHexKey As String, ByVal strCurveName As String, ByVal nOptions As Long) As Long
nRet = ECC_ReadKeyByCurve(strOutput, Len(strOutput), strHexKey, strCurveName, nOptions)
long __stdcall ECC_ReadKeyByCurve(char *szOutput, long nOutChars, const char *szHexKey, const char *szCurveName, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a nonzero error code.
Public Function eccReadKeyByCurve (szHexKey As String, szCurveName As String, Optional nOptions As Long = 0) As String
static std::string dipki::Ecc::ReadKeyByCurve (std::string hexKey, Curve curve, Publicity publicity=Publicity::PrivateKey)
static Ecc.read_key_by_curve(keyhex, curvename, ispublic=False)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The output string is an ephemeral internal key string valid only for the current session. This internal key string can be used directly by functions such as ECC_DHSharedSecret or SIG_SignData. You can analyze the key string using ECC_QueryKey or save it in one of the supported key file formats using ECC_SaveKey or ECC_SaveEncKey. The input string is expected to be the hexadecimal (base16) representation of a private or public key.
NIST/SEC/Brainpool curves: A private key is represented by the hexadecimal encoding of its integer value encoded in octets
as per section 3 of [RFC5915].
A public key is represented by the hexadecimal encoding of the octet string as defined in section 4.3.6 of
[X9-63]; that is, 04||Px||Py.
Only the uncompressed form of a public key (beginning "04") is supported due to patent issues.
It is an error if the key value is out of range or not a valid point on the curve.
Safe curves: Both private and public keys are represented by the hexadecimal encoding of its integer value encoded as a byte array in little-endian form as per [RFC7748] and [RFC8032]. For Ed25519 and X25519, the input string szHexKey is always expected to be a hexadecimal representation of exactly 32 bytes. Set nOptions as PKI_ECC_PRIVATE_KEY (default 0) or PKI_ECC_PUBLIC_KEY to indicate whether the key value represents a private or public key, respectively. Any 32-byte key string will be accepted as input and any required bit masking (e.g. for an X25519 private key) will be applied before use.
Supported curve names for szCurveName are:
| Curve name | Alternative names | Remarks |
|---|---|---|
secp192r1 | P-192, P_192, prime192v1 | NIST |
secp224r1 | P-224, P_224 | NIST |
secp256r1 | P-256, P_256, prime256v1 | NIST |
secp384r1 | P-384, P_384 | NIST |
secp521r1 | P-521, P_521 | NIST |
secp256k1 | SEC/Bitcoin | |
Ed25519 | Safe EdDSA curve [RFC8032] | |
Ed448 | Safe EdDSA curve [RFC8032] | |
X25519 | Safe ECDH curve [RFC7748] | |
X448 | Safe ECDH curve [RFC7748] | |
brainpoolP256r1 | [RFC5639] | |
brainpoolP384r1 | [RFC5639] | |
brainpoolP512r1 | [RFC5639] |
Dim nRet As Long Dim nChars As Long Dim strIntKey As String Dim strHexKey As String Dim strCurveName As String Dim strQuery As String Dim strBuffer As String Dim strBase58 As String Dim abTemp() As Byte Dim nBytes As Long ' 1. A NIST P-192 public key in X9.63 uncompressed format strHexKey = _ "0496C248BE456192FA1380CCF615D171452F41FF31B92BA733524FD77168DEA4425A3EA8FD79B98DC7AFE83C86DCC39A96" strCurveName = "prime192v1" ' A synonym for "P-192" Debug.Print "KEYHEX: " & strHexKey Debug.Print "CURVE: " & strCurveName ' Find required length of internal key string nChars = ECC_ReadKeyByCurve("", 0, strHexKey, strCurveName, 0) Debug.Print "ECC_ReadKeyByCurve returns " & nChars & " (expected +ve)" ' Dimension the string to receive output strIntKey = String(nChars, " ") ' Read into internal key string nChars = ECC_ReadKeyByCurve(strIntKey, Len(strIntKey), strHexKey, strCurveName, 0) ' Find the key size in bits strQuery = "keyBits" nRet = ECC_QueryKey("", 0, strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" & nRet & " (expected +ve)" ' Is it a private or public key? strQuery = "isPrivate" nRet = ECC_QueryKey("", 0, strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" & nRet & " (expected 0)" Debug.Print ' 2. A Bitcoin private key in base58 form strBase58 = "6ACCbmy9qwiFcuVgvxNNwMPfoghobzznWrLs3v7t3RmN" Debug.Print "KEYB58: " & strBase58 strCurveName = "secp256k1" ' Convert to a hex string nBytes = CNV_Base58ToBytes(0, 0, strBase58) Debug.Assert (nBytes > 0) ReDim abTemp(nBytes - 1) nBytes = CNV_Base58ToBytes(abTemp(0), nBytes, strBase58) strHexKey = cnvHexStrFromBytes(abTemp) Debug.Print "KEYHEX: " & strHexKey Debug.Print "CURVE: " & strCurveName ' Find required length of internal key string nChars = ECC_ReadKeyByCurve("", 0, strHexKey, strCurveName, 0) Debug.Print "ECC_ReadKeyByCurve returns " & nChars & " (expected +ve)" ' Dimension the string to receive output strIntKey = String(nChars, " ") ' Read into internal key string nChars = ECC_ReadKeyByCurve(strIntKey, Len(strIntKey), strHexKey, strCurveName, 0) ' Find the key size in bits strQuery = "keyBits" nRet = ECC_QueryKey("", 0, strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" & nRet & " (expected +ve)" ' Is it a private or public key? strQuery = "isPrivate" nRet = ECC_QueryKey("", 0, strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" & nRet & " (expected 1)" ' Extract the public key in hex form strQuery = "publicKey" nChars = ECC_QueryKey("", 0, strIntKey, strQuery, 0) strBuffer = String(nChars, " ") nChars = ECC_QueryKey(strBuffer, Len(strBuffer), strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" If nChars > 0 Then Debug.Print "[" & Left(strBuffer, nChars) & "]"
KEYHEX: 0496C248BE456192FA1380CCF615D171452F41FF31B92BA733524FD77168DEA4425A3EA8FD79B98DC7AFE83C86DCC39A96
CURVE: prime192v1
ECC_ReadKeyByCurve returns 100 (expected +ve)
ECC_QueryKey('keyBits')=192 (expected +ve)
ECC_QueryKey('isPrivate')=0 (expected 0)
KEYB58: 6ACCbmy9qwiFcuVgvxNNwMPfoghobzznWrLs3v7t3RmN
KEYHEX: 4CA55366ADE9E9BC12319DFFC246F64EB7FA07755925B92CEFC92D740DBC51ED
CURVE: secp256k1
ECC_ReadKeyByCurve returns 196 (expected +ve)
ECC_QueryKey('keyBits')=256 (expected +ve)
ECC_QueryKey('isPrivate')=1 (expected 1)
ECC_QueryKey('publicKey')=
[04654bacc2fc7a3bde0f8eb95dc5aac9ba1df732255cf7f2eb7e1e8e6edbb1f4188ff3752ac4bdf1e3a31a488747745dddcbabd33a10c3b52d737c092851da13c0]
Dim curveName As String Dim alicePrivateKeyHex As String Dim ourPrivateKey As String Dim nChars As Long curveName = "X25519" alicePrivateKeyHex = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" ' The old long way... nChars = ECC_ReadKeyByCurve(vbNullString, 0, alicePrivateKeyHex, curveName, PKI_ECC_PRIVATE_KEY) Debug.Assert nChars > 0 ourPrivateKey = String(nChars, " ") nChars = ECC_ReadKeyByCurve(ourPrivateKey, nChars, alicePrivateKeyHex, curveName, PKI_ECC_PRIVATE_KEY) ' The new short way with a wrapper function ourPrivateKey = eccReadKeyByCurve(alicePrivateKeyHex, curveName, PKI_ECC_PRIVATE_KEY) Debug.Assert Len(ourPrivateKey) > 0 Debug.Print "Key curve=" & eccQueryKey(ourPrivateKey, "curveName", 0) & " keyBits=" & eccQueryKey(ourPrivateKey, "keyBits", 0)
Dim strCurveName As String Dim ourPrivateKey As String Dim theirPublicKey As String Dim lpZZ() As Byte ' Ref: RFC7748 Section 6.1 Const alicePrivateKeyHex As String = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" Const alicePublicKeyHex As String = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a" Const bobPrivateKeyHex As String = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb" Const bobPublicKeyHex As String = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f" strCurveName = "X25519" ' 1. Alice's private + Bob's public ourPrivateKey = eccReadKeyByCurve(alicePrivateKeyHex, strCurveName, PKI_ECC_PRIVATE_KEY) Debug.Print "Our key has " & eccQueryKey(ourPrivateKey, "keyBits") & " bits and is a " & _ IIf(eccQueryKey(ourPrivateKey, "isPrivate") = "1", "Private", "Public") & " key" theirPublicKey = eccReadKeyByCurve(bobPublicKeyHex, strCurveName, PKI_ECC_PUBLIC_KEY) Debug.Print "Their key has " & eccQueryKey(theirPublicKey, "keyBits") & " bits and is a " & _ IIf(eccQueryKey(theirPublicKey, "isPrivate") = "1", "Private", "Public") & " key" ' Compute shared secret lpZZ = eccDHSharedSecret(ourPrivateKey, theirPublicKey) Debug.Print "ZZ=" & cnvHexStrFromBytes(lpZZ) Debug.Print "OK=4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" ' 2. Bob's private + Alice's public ourPrivateKey = eccReadKeyByCurve(bobPrivateKeyHex, strCurveName, PKI_ECC_PRIVATE_KEY) Debug.Print "Our key has " & eccQueryKey(ourPrivateKey, "keyBits") & " bits and is a " & _ IIf(eccQueryKey(ourPrivateKey, "isPrivate") = "1", "Private", "Public") & " key" theirPublicKey = eccReadKeyByCurve(alicePublicKeyHex, strCurveName, PKI_ECC_PUBLIC_KEY) Debug.Print "Their key has " & eccQueryKey(theirPublicKey, "keyBits") & " bits and is a " & _ IIf(eccQueryKey(theirPublicKey, "isPrivate") = "1", "Private", "Public") & " key" ' Compute shared secret lpZZ = eccDHSharedSecret(ourPrivateKey, theirPublicKey) Debug.Print "ZZ=" & cnvHexStrFromBytes(lpZZ) Debug.Print "OK=4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
Reads an EC private key from a file into an internal key string.
Public Declare Function ECC_ReadPrivateKey Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strKeyFileOrString As String, ByVal strPassword As String, ByVal nOptions As Long) As Long
nRet = ECC_ReadPrivateKey(strOutput, Len(strOutput), strKeyFileOrString, strPassword, nOptions)
long __stdcall ECC_ReadPrivateKey(char *szOutput, long nOutChars, const char *szKeyFileOrString, const char *szPassword, long nOptions);
"".If successful, the return value is the number of characters in or required for the output string; otherwise it returns a nonzero error code.
Public Function eccReadPrivateKey (szKeyFileOrString As String, Optional szPassword As String = "", Optional nOptions As Long = 0) As String
static std::string dipki::Ecc::ReadPrivateKey (std::string keyFileOrString, std::string password="")
static Ecc.read_private_key(keyfileorstr, password="")
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
This reads both encrypted private keys and the unencrypted PKCS#8 PrivateKeyInfo and ECPrivateKey formats.
Set szPassword as the empty string "" if not required.
Dim nRet As Long Dim nChars As Long Dim strIntKey As String Dim strKeyFile As String Dim strPassword As String Dim strNewKeyFile As String Dim strTypeName As String Dim strFileName As String strKeyFile = "myeckeyp256.p8" strPassword = "password" ' Find required length of internal key string nChars = ECC_ReadPrivateKey("", 0, strKeyFile, strPassword, 0) Debug.Print "ECC_ReadPrivateKey returns " & nChars & " (expected +ve)" ' Dimension the string to receive output strIntKey = String(nChars, " ") ' Read it in nChars = ECC_ReadPrivateKey(strIntKey, Len(strIntKey), strKeyFile, strPassword, 0) ' Caution: internal key string is only valid for the current session Debug.Print "[" & strIntKey & "]" ' Now save in a different format: ECPrivatekey in PEM encoding strNewKeyFile = "myeckey.pem" nRet = ECC_SaveKey(strNewKeyFile, strIntKey, PKI_KEY_FORMAT_PEM) Debug.Print "ECC_SaveKey returns " & nRet & " (expected 0)" ' Check the types of file we made strTypeName = String(PKI_ASN1_TYPE_MAXCHARS, " ") strFileName = strNewKeyFile nChars = ASN1_Type(strTypeName, Len(strTypeName), strFileName, 0) If nChars > 0 Then Debug.Print strFileName & ": " & Left(strTypeName, nChars)
ECC_ReadPrivateKey returns 100 (expected +ve) [PVECwcBFxO1TkZ3D/O6...nNWDXV9xuIUuVZqCO5] ECC_SaveKey returns 0 (expected 0) myeckey.pem: EC PRIVATE KEY
The output file should look similar to the following:
-----BEGIN EC PRIVATE KEY----- MDECAQEEIAlVzJkEMwIF+gBVnbyuXJeMQqL5b8HWYbZvYXMx7wc4oAoGCCqGSM49 AwEH -----END EC PRIVATE KEY-----
Dim strIntKey As String ' Read in public key from file strIntKey = eccReadPublicKey("myeckeyp256.pub") Debug.Assert Len(strIntKey) > 0 Debug.Print "Key curve=" & eccQueryKey(strIntKey, "curveName", 0) & " keyBits=" & _ eccQueryKey(strIntKey, "keyBits", 0) & _ " and is a " & _ IIf(eccQueryKey(strIntKey, "isPrivate") = "1", "Private", "Public") & " key" Debug.Print eccQueryKey(strIntKey, "publicKey") Debug.Print "KeyHashCode=0x" & Hex(ECC_KeyHashCode(strIntKey)) ' Read in private key from file strIntKey = eccReadPrivateKey("myeckeyp256.p8", "password") Debug.Assert Len(strIntKey) > 0 Debug.Print "Key curve=" & eccQueryKey(strIntKey, "curveName", 0) & " keyBits=" & _ eccQueryKey(strIntKey, "keyBits", 0) & _ " and is a " & _ IIf(eccQueryKey(strIntKey, "isPrivate") = "1", "Private", "Public") & " key" Debug.Print eccQueryKey(strIntKey, "publicKey") Debug.Print "KeyHashCode=0x" & Hex(ECC_KeyHashCode(strIntKey)) ' Derive public key from private key strIntKey = eccPublicKeyFromPrivate(strIntKey) Debug.Assert Len(strIntKey) > 0 Debug.Print "Key curve=" & eccQueryKey(strIntKey, "curveName", 0) & " keyBits=" & _ eccQueryKey(strIntKey, "keyBits", 0) & _ " and is a " & _ IIf(eccQueryKey(strIntKey, "isPrivate") = "1", "Private", "Public") & " key" Debug.Print eccQueryKey(strIntKey, "publicKey") Debug.Print "KeyHashCode=0x" & Hex(ECC_KeyHashCode(strIntKey))
ECC_ReadPublicKey ECC_QueryKey
Reads an EC public key from a file into an internal key string.
Public Declare Function ECC_ReadPublicKey Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strKeyFileOrString As String, ByVal nOptions As Long) As Long
nRet = ECC_ReadPublicKey(strOutput, Len(strOutput), strKeyFileOrString, nOptions)
long __stdcall ECC_ReadPublicKey(char *szOutput, long nOutChars, const char *szKeyFileOrString, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function eccReadPublicKey (szKeyFileOrString As String, Optional nOptions As Long = 0) As String
static std::string dipki::Ecc::ReadPublicKey (std::string keyFileOrString)
static Ecc.read_public_key(keyfileorstr)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
[New in v12.0] An EC public key can also be read directly from an X.509 certificate (or its base64 representation).
Dim nRet As Long Dim nChars As Long Dim strIntKey As String Dim strKeyFile As String Dim strQuery As String strKeyFile = "myeckeyp521.pub" Debug.Print "FILE: " & strKeyFile ' Find required length of internal key string nChars = ECC_ReadPublicKey("", 0, strKeyFile, 0) Debug.Print "ECC_ReadPublicKey returns " & nChars & " (expected +ve)" ' Dimension the string to receive output strIntKey = String(nChars, " ") ' Read into internal key string nChars = ECC_ReadPublicKey(strIntKey, Len(strIntKey), strKeyFile, 0) Debug.Print "[" & strIntKey & "]" ' Find the key size in bits (NB returned directly) strQuery = "keyBits" nRet = ECC_QueryKey("", 0, strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" & nRet & " (expected +ve)" ' Is it a private or public key? strQuery = "isPrivate" nRet = ECC_QueryKey("", 0, strIntKey, strQuery, 0) Debug.Print "ECC_QueryKey('" & strQuery & "')=" & nRet & " (expected 0)"
FILE: myeckeyp521.pub
ECC_ReadPublicKey returns 212 (expected +ve)
[MIGbMBAGByqGSM49AgEGBSuB ... NARus1tKwwWhEJGs=]
ECC_QueryKey('keyBits')=521 (expected +ve)
ECC_QueryKey('isPrivate')=0 (expected 0)
Dim strIntKey As String ' Read in public key from file strIntKey = eccReadPublicKey("myeckeyp256.pub") Debug.Assert Len(strIntKey) > 0 Debug.Print "Key curve=" & eccQueryKey(strIntKey, "curveName", 0) & " keyBits=" & _ eccQueryKey(strIntKey, "keyBits", 0) & _ " and is a " & _ IIf(eccQueryKey(strIntKey, "isPrivate") = "1", "Private", "Public") & " key" Debug.Print eccQueryKey(strIntKey, "publicKey") Debug.Print "KeyHashCode=0x" & Hex(ECC_KeyHashCode(strIntKey)) ' Read in private key from file strIntKey = eccReadPrivateKey("myeckeyp256.p8", "password") Debug.Assert Len(strIntKey) > 0 Debug.Print "Key curve=" & eccQueryKey(strIntKey, "curveName", 0) & " keyBits=" & _ eccQueryKey(strIntKey, "keyBits", 0) & _ " and is a " & _ IIf(eccQueryKey(strIntKey, "isPrivate") = "1", "Private", "Public") & " key" Debug.Print eccQueryKey(strIntKey, "publicKey") Debug.Print "KeyHashCode=0x" & Hex(ECC_KeyHashCode(strIntKey)) ' Derive public key from private key strIntKey = eccPublicKeyFromPrivate(strIntKey) Debug.Assert Len(strIntKey) > 0 Debug.Print "Key curve=" & eccQueryKey(strIntKey, "curveName", 0) & " keyBits=" & _ eccQueryKey(strIntKey, "keyBits", 0) & _ " and is a " & _ IIf(eccQueryKey(strIntKey, "isPrivate") = "1", "Private", "Public") & " key" Debug.Print eccQueryKey(strIntKey, "publicKey") Debug.Print "KeyHashCode=0x" & Hex(ECC_KeyHashCode(strIntKey))
ECC_ReadPrivateKey ECC_QueryKey
Saves an internal EC private key string to an encrypted private key file.
Public Declare Function ECC_SaveEncKey Lib "diCrPKI.dll" (ByVal strFileOut As String, ByVal strIntKeyString As String, ByVal strPassword As String, ByVal strParams As String, ByVal nOptions As Long) As Long
nRet = ECC_SaveEncKey(strFileOut, strIntKeyString, strPassword, strParams, nOptions)
long __stdcall ECC_SaveEncKey(const char *szFileOut, const char *szIntKeyString, const char *szPassword, const char *szParams, long nOptions);
"" for defaults.
Otherwise include a set of attribute-value pairs separated by a semi-colon ";" to set options from the following
count=<nnn> to set the iteration count used in the PBKDF method,
e.g. "count=5000;" [default=2048]
prf=<hmac-name> to change the HMAC algorithm used in the PBKDF2 method,
e.g. "prf=hmacWithSHA256;" [default=hmacwithSHA1]
"pbeWithSHAAnd3-KeyTripleDES-CBC" (default)des-EDE3-CBCaes128-CBCaes192-CBCaes256-CBCIf successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function eccSaveEncKey (szOutputFile As String, szKeyStr As String, szPassword As String, Optional szParams As String = "", Optional nOptions As Long = 0) As Long
static int dipki::Ecc::SaveEncKey (std::string outputFile, std::string internalKey, std::string password, PbeScheme pbes=PbeScheme::Default, std::string paramString="", Format fileFormat=Format::Binary)
static Ecc.save_enc_key(outputfile, intkeystr, password, pbescheme=0, params='', fileformat=0)
Use this function to save a private key in a new encrypted file format, perhaps with stronger encryption. Use the PKI_KEY_FORMAT_PEM flag to save in PEM-encoded format. You must first read in the old private key file into an "internal" private key string which is only valid for the current session.
Valid values for the "prf" parameter in szParams are:
hmacWithSHA1 (default)hmacWithSHA224hmacWithSHA256hmacWithSHA384hmacWithSHA512
Set szParams as the empty string "" for defaults.
Dim nRet As Long Dim nChars As Long Dim strIntKey As String Dim strPriKeyFile As String Dim strPassword As String Dim strNewKeyFile As String Dim strTypeName As String Dim strFileName As String strPriKeyFile = "myeckeyp256.p8" strPassword = "password" ' Find required length of internal key string nChars = ECC_ReadPrivateKey("", 0, strPriKeyFile, strPassword, 0) Debug.Print "ECC_ReadPrivateKey returns " & nChars & " (expected +ve)" ' Dimension the string to receive output strIntKey = String(nChars, " ") ' Read it in nChars = ECC_ReadPrivateKey(strIntKey, Len(strIntKey), strPriKeyFile, strPassword, 0) Debug.Print "[" & strIntKey & "]" ' Now save in a different format: ECPrivatekey strNewKeyFile = "myeckey.key" nRet = ECC_SaveKey(strNewKeyFile, strIntKey, 0) Debug.Print "ECC_SaveKey returns " & nRet & " (expected 0)" ' Check the types of file we made strTypeName = String(PKI_ASN1_TYPE_MAXCHARS, " ") strFileName = strNewKeyFile nChars = ASN1_Type(strTypeName, Len(strTypeName), strFileName, 0) If nChars > 0 Then Debug.Print strFileName & ": " & Left(strTypeName, nChars)
ECC_ReadPrivateKey returns 100 (expected +ve) [PVECvfqrR9ge+DBQVJtnBBrw6gH+qmnZSX7apDuXoWcwmvIWLXNbXHG3Bo1cAXGuLUzIeWyb4M5G2aUnn/3Y/9d1/KjQjTnNXeky] ECC_SaveKey returns 0 (expected 0) myeckey.key: EC PRIVATE KEY
ECC_ReadPrivateKey ECC_SaveKey
Saves an internal EC key string to an unencrypted key file.
Public Declare Function ECC_SaveKey Lib "diCrPKI.dll" (ByVal strFileOut As String, ByVal strIntKeyString As String, ByVal nOptions As Long) As Long
nRet = ECC_SaveKey(strFileOut, strIntKeyString, nOptions)
long __stdcall ECC_SaveKey(const char *szFileOut, const char *szIntKeyString, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function eccSaveKey (szOutputFile As String, szKeyStr As String, Optional nOptions As Long = 0) As Long
static int dipki::Ecc::SaveKey (std::string outputFile, std::string internalKey, KeyType keyType=KeyType::Default, Format fileFormat=Format::Binary)
static Ecc.save_key(outputfile, intkeystr, keytype=0, fileformat=0)
EC public keys are always saved in SubjectPublicKeyInfo format [RFC5480].
By default, NIST/SEC curve private keys are saved in ECPrivateKey format [RFC5915].
Use the PKI_KEY_TYPE_PKCS8 option to save in PKCS#8 PrivateKeyInfo format [RFC5208].
[New in v22.0] Safe curve private keys (X25519, Ed25519, X448 and Ed448) are always saved in PKCS#8 v2 OneAsymmetricKey
format including the public key [RFC5958].
Add the option PKI_KEY_LEGACY to save in older PKCS#8 v1 PrivateKeyInfo format [RFC5208]
excluding the public key.
To save a private key in encrypted form, use ECC_SaveEncKey.
Dim nRet As Long Dim nChars As Long Dim strIntKey As String Dim strKeyFile As String Dim strPassword As String Dim strNewKeyFile As String Dim strTypeName As String Dim strFileName As String strKeyFile = "myeckeyp256.p8" strPassword = "password" Debug.Print "FILE: " & strKeyFile ' Find required length of internal key string nChars = ECC_ReadPrivateKey("", 0, strKeyFile, strPassword, 0) Debug.Print "ECC_ReadPrivateKey returns " & nChars & " (expected +ve)" ' Dimension the string to receive output strIntKey = String(nChars, " ") ' Read it in nChars = ECC_ReadPrivateKey(strIntKey, Len(strIntKey), strKeyFile, strPassword, 0) ' Caution: internal key string is only valid for the current session Debug.Print "[" & strIntKey & "]" ' Now save in a different format: ECPrivatekey in PEM encoding strNewKeyFile = "myeckey.pem" nRet = ECC_SaveKey(strNewKeyFile, strIntKey, PKI_KEY_FORMAT_PEM) Debug.Print "ECC_SaveKey returns " & nRet & " (expected 0)" ' Check the type of file we made strTypeName = String(PKI_ASN1_TYPE_MAXCHARS, " ") strFileName = strNewKeyFile nChars = ASN1_Type(strTypeName, Len(strTypeName), strFileName, 0) If nChars > 0 Then Debug.Print strFileName & ": " & Left(strTypeName, nChars)
FILE: myeckeyp256.p8 ECC_ReadPrivateKey returns 100 (expected +ve) [PVECF7UtCxnQIin+PBxnvYk8GsAsMbPfKYUnfZv/EU/oSeJtW1UAt1QMZT60Solrg6PtKLHsGlWT8IxgKTfzIf3+NK/Ulq0+z6Id] ECC_SaveKey returns 0 (expected 0) myeckey.pem: EC PRIVATE KEY
ECC_ReadPrivateKey ECC_ReadPublicKey ECC_SaveEncKey ECC_PublicKeyFromPrivate
Creates a message digest hash as a byte array from byte data. The hash algorithm to use is passed in the options parameter.
Public Declare Function HASH_Bytes Lib "diCrPKI.dll"
(ByRef lpDigest As Byte, ByVal nDigLen As Long, ByRef lpMessage As Byte,
ByVal nMsgLen As Long, ByVal nOptions As Long) As Long
nRet = HASH_Bytes(lpDigest(0), nDigLen, lpMessage(0), nMsgLen, nOptions) ' Note the "(0)" after the byte array parameters
long __stdcall HASH_Bytes(unsigned char *lpOutput, long nOutBytes, const void *lpMessage, long nMsgLen, long nOptions);
RIPEMD160(SHA256(m))HASH(HASH(m))If successful, the return value is the number of bytes in the hash digest array; otherwise it returns a negative error code.
Public Function hashBytes (lpMessage() As Byte, nOptions As Long) As Byte()
Hash.BytesFromBytes Method
Hash.Double Method
static bvec_t dipki::Hash::Bytes (const bvec_t &data, Alg alg=Alg::Sha1)
static Hash.double(data, alg=Alg.SHA1)
static Hash.data(data, alg=Alg.SHA1)
static Hash.double(data, alg=Alg.SHA1)
Specify a zero nDigLen parameter to find out the required length of the output array.
The maximum possible length is PKI_MAX_HASH_BYTES.
Hint: SHA-1 requires 20 bytes; MD5 and MD2 require 16 bytes; SHA-512 requires 64.
The final digest will be truncated to the specified length if less than the expected size.
Dim nRet As Long
Dim abDigest() As Byte
Dim abMessage() As Byte
Dim nMsgLen As Long
' Set up message to be hashed
abMessage = StrConv("abc", vbFromUnicode)
nMsgLen = UBound(abMessage) + 1
' Pre-dimension digest array (NB zero-based so subtract one)
ReDim abDigest(PKI_MAX_HASH_BYTES - 1)
' Create default hash (SHA1)
nRet = HASH_Bytes(abDigest(0), PKI_MAX_HASH_BYTES, abMessage(0), nMsgLen, 0)
If nRet > 0 Then ReDim Preserve abDigest(nRet - 1)
Debug.Print nRet, cnvHexStrFromBytes(abDigest)
' Repeat for MD5
ReDim abDigest(PKI_MAX_HASH_BYTES - 1)
nRet = HASH_Bytes(abDigest(0), PKI_MAX_HASH_BYTES, abMessage(0), nMsgLen, PKI_HASH_MD5)
If nRet > 0 Then ReDim Preserve abDigest(nRet - 1)
Debug.Print nRet, cnvHexStrFromBytes(abDigest)
The above example should produce the following output:
20 A9993E364706816ABA3E25717850C26C9CD0D89D 16 900150983CD24FB0D6963F7D28E17F72
Dim strDigest As String Dim lpMessage() As Byte Dim lpDigest() As Byte ' Hex <-- Hex strDigest = hashHexFromHex("616263", PKI_HASH_SHA256) ' "abc" in hex Debug.Print strDigest lpMessage = StrConv("abc", vbFromUnicode) ' "abc" in a byte array ' Hex <-- Bytes strDigest = hashHexFromBytes(lpMessage, PKI_HASH_SHA256) Debug.Print strDigest ' Bytes <-- Bytes lpDigest = hashBytes(lpMessage, PKI_HASH_SHA256) Debug.Print cnvHexStrFromBytes(lpDigest) ' Hex <-- File strDigest = hashHexFromFile("abc.txt", PKI_HASH_SHA256) ' "abc" in a text file Debug.Print strDigest ' Bytes <-- File lpDigest = hashFile("abc.txt", PKI_HASH_SHA256) Debug.Print cnvHexStrFromBytes(lpDigest) Debug.Print "OK=" & "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"
Dim strDigest As String Dim lpMessage() As Byte Dim lpDigest() As Byte lpDigest = hashBytes(lpMessage, PKI_HASH_SHA256) Debug.Print cnvHexStrFromBytes(lpDigest) lpDigest = hashBytes(lpMessage, PKI_HASH_SHA256) Debug.Print cnvHexStrFromBytes(lpDigest) strDigest = hashHexFromBytes(lpMessage, PKI_HASH_SHA256) Debug.Print strDigest strDigest = hashHexFromBytes(lpMessage, PKI_HASH_SHA512) Debug.Print strDigest strDigest = hashHexFromBytes(lpMessage, PKI_HASH_SHA512) Debug.Print strDigest
Creates a message digest hash in byte format for a file. The hash algorithm to use is passed in the options parameter.
Public Declare Function HASH_File Lib "diCrPKI.dll"
(ByRef lpDigest As Byte, ByVal nDigLen As Long, ByVal strFileName As String,
ByVal nOptions As Long) As Long
nRet = HASH_File(lpDigest(0), nDigLen, strFileName, nOptions)
long __stdcall HASH_File(unsigned char *lpOutput, long nOutBytes, const char *szFileName, long nOptions);
RIPEMD160(SHA256(m))HASH(HASH(m))If successful, the return value is the number of bytes in the hash digest array; otherwise it returns a negative error code.
Public Function hashFile (szFileName As String, nOptions As Long) As Byte()
static bvec_t dipki::Hash::File (const std::string &fileName, Alg alg=Alg::Sha1, FileMode mode=FileMode::Binary)
static Hash.file(filename, alg=Alg.SHA1)
Specify a zero nOutBytes parameter to find out the required length of the output array.
The maximum size will be PKI_MAX_HASH_BYTES.
The final digest will be truncated to the specified length if less than the expected size.
Add the option PKI_HASH_MODE_TEXT to work in "text" mode where CR-LF pairs are treated
as a single newline (LF) character.
(This option is provided if you need to pass hash digests of text files between Windows and Unix systems.)
The default mode is "binary" where each byte is treated individually.
Only ANSI characters are supported in file names and paths.
Dim nRet As Long
Dim abDigest() As Byte
Dim sFileName As String
' File to be hashed contains a total of 13 bytes: "hello world" plus CR-LF
' 68 65 6c 6c 6f 20 77 6f 72 6c 64 0d 0a hello world..
sFileName = "hello.txt"
' Pre-dimension digest array - do this each time
ReDim abDigest(PKI_MAX_HASH_BYTES)
' Create default hash (SHA1) in binary mode
nRet = HASH_File(abDigest(0), PKI_MAX_HASH_BYTES, sFileName, 0)
If nRet > 0 Then ReDim Preserve abDigest(nRet - 1)
Debug.Print nRet, cnvHexStrFromBytes(abDigest)
' Use SHA1 in "text" mode
ReDim abDigest(PKI_MAX_HASH_BYTES)
nRet = HASH_File(abDigest(0), PKI_MAX_HASH_BYTES, sFileName, PKI_HASH_MODE_TEXT)
If nRet > 0 Then ReDim Preserve abDigest(nRet - 1)
Debug.Print nRet, cnvHexStrFromBytes(abDigest)
' Use MD5
ReDim abDigest(PKI_MAX_HASH_BYTES)
nRet = HASH_File(abDigest(0), PKI_MAX_HASH_BYTES, sFileName, PKI_HASH_MD5)
If nRet > 0 Then ReDim Preserve abDigest(nRet - 1)
Debug.Print nRet, cnvHexStrFromBytes(abDigest)
' Use MD5 in "text" mode
ReDim abDigest(PKI_MAX_HASH_BYTES)
nRet = HASH_File(abDigest(0), PKI_MAX_HASH_BYTES, sFileName, PKI_HASH_MD5 Or PKI_HASH_MODE_TEXT)
If nRet > 0 Then ReDim Preserve abDigest(nRet - 1)
Debug.Print nRet, cnvHexStrFromBytes(abDigest)
This should produce the following output:
20 88A5B867C3D110207786E66523CD1E4A484DA697 20 22596363B3DE40B06F981FB85D82312E8C0ED511 16 A0F2A3C1DCD5B1CAC71BF0C03F2FF1BD 16 6F5902AC237024BDD0C176CB93063DC4
Dim strDigest As String Dim lpMessage() As Byte Dim lpDigest() As Byte ' Hex <-- Hex strDigest = hashHexFromHex("616263", PKI_HASH_SHA256) ' "abc" in hex Debug.Print strDigest lpMessage = StrConv("abc", vbFromUnicode) ' "abc" in a byte array ' Hex <-- Bytes strDigest = hashHexFromBytes(lpMessage, PKI_HASH_SHA256) Debug.Print strDigest ' Bytes <-- Bytes lpDigest = hashBytes(lpMessage, PKI_HASH_SHA256) Debug.Print cnvHexStrFromBytes(lpDigest) ' Hex <-- File strDigest = hashHexFromFile("abc.txt", PKI_HASH_SHA256) ' "abc" in a text file Debug.Print strDigest ' Bytes <-- File lpDigest = hashFile("abc.txt", PKI_HASH_SHA256) Debug.Print cnvHexStrFromBytes(lpDigest) Debug.Print "OK=" & "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"
Creates a message digest hash in hexadecimal format from byte (or string) data. The hash algorithm to use is passed in the options parameter.
Public Declare Function HASH_HexFromBytes Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nOutChars As Long, ByRef lpMessage As Byte, ByVal nMsgLen As Long,
ByVal nOptions As Long) As Long
Alternative for VB6/VBA only:-
Public Declare Function HASH_HexFromString Lib "diCrPKI.dll" Alias "HASH_HexFromBytes"
(ByVal strOutput As String, ByVal nOutChars As Long, ByVal strMessage As String, ByVal nMsgLen As Long,
ByVal nOptions As Long) As Long
nRet = HASH_HexFromBytes(strOutput, nOutChars, lpMessage(0), nMsgLen, nOptions)
nRet = HASH_HexFromString(strOutput, nOutChars, strMessage, nMsgLen, nOptions)
long __stdcall HASH_HexFromBytes(char *szOutput, long nOutChars, const void *lpMessage, long nMsgLen, long nOptions);
RIPEMD160(SHA256(m))HASH(HASH(m))If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function hashHexFromBytes (lpMessage() As Byte, nOptions As Long) As String
Hash.HexFromBytes Method
Hash.HexFromString Method
static std::string dipki::Hash::HexFromBytes (const bvec_t &data, Alg alg=Alg::Sha1)
static Hash.hex_from_data(data, alg=Alg.SHA1)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The maximum number of output characters is PKI_MAX_HASH_CHARS (C/C++ users add one).
The final digest will be truncated to the specified length if less than the expected size.
Dim nRet As Long Dim sDigest As String Dim abMessage() As Byte ' Set up message to be hashed in unambiguous Byte format abMessage = StrConv("abc", vbFromUnicode) ' Pre-dimension digest string sDigest = String(PKI_MAX_HASH_CHARS, " ") ' Create default hash (SHA1) nRet = HASH_HexFromBytes(sDigest, Len(sDigest), abMessage(0), 3, 0) Debug.Print nRet, Left(sDigest, nRet) ' Explicitly use SHA1 nRet = HASH_HexFromBytes(sDigest, Len(sDigest), abMessage(0), 3, PKI_HASH_SHA1) Debug.Print nRet, Left(sDigest, nRet) ' Pre-dimension digest string and use MD5 sDigest = String(PKI_MD5_CHARS, " ") nRet = HASH_HexFromBytes(sDigest, Len(sDigest), abMessage(0), 3, PKI_HASH_MD5) Debug.Print nRet, sDigest ' Pre-dimension digest string and use MD2 sDigest = String(PKI_MD5_CHARS, " ") nRet = HASH_HexFromBytes(sDigest, Len(sDigest), abMessage(0), 3, PKI_HASH_MD2) Debug.Print nRet, sDigest ' Make output string shorter - only get back that many chars sDigest = String(16, " ") nRet = HASH_HexFromBytes(sDigest, Len(sDigest), abMessage(0), 3, PKI_HASH_SHA1) Debug.Print nRet, sDigest
The above example should produce the following output:
40 a9993e364706816aba3e25717850c26c9cd0d89d 40 a9993e364706816aba3e25717850c26c9cd0d89d 32 900150983cd24fb0d6963f7d28e17f72 32 da853b0d3f88d99b30283a69e6ded6bb 16 a9993e364706816a
Alternative using String type directly (assumes 8-bit ANSI characters in strMessage):
Dim nRet As Long
Dim sDigest As String
Dim strMessage As String
strMessage = "abc"
' Pre-dimension digest string
sDigest = String(40, " ")
' Create default hash (SHA1)
nRet = HASH_HexFromString(sDigest, Len(sDigest), strMessage, Len(strMessage), 0)
Debug.Print nRet, sDigest
Example in C code (in C we are less fussed about the distinction between char
and unsigned char types when dealing with nonzero ANSI characters):
long lRet;
char szDigest[PKI_MAX_HASH_CHARS+1]; /* NB add one */
char message[] = "abc";
/* Compute default SHA-1 digest */
lRet = HASH_HexFromBytes(szDigest, sizeof(szDigest)-1,
(unsigned char*)message, strlen(message), 0);
assert(lRet > 0);
printf("SHA1('abc')=%s\n", szDigest);
/* Compute MD5 digest */
lRet = HASH_HexFromBytes(szDigest, sizeof(szDigest)-1,
(unsigned char*)message, strlen(message), PKI_HASH_MD5);
assert(lRet > 0);
printf("MD5('abc')=%s\n", szDigest);
/* Compute MD2 digest */
lRet = HASH_HexFromBytes(szDigest, sizeof(szDigest)-1,
(unsigned char*)message, strlen(message), PKI_HASH_MD2);
assert(lRet > 0);
printf("MD2('abc')=%s\n", szDigest);
This should produce the output
SHA1('abc')=a9993e364706816aba3e25717850c26c9cd0d89d
MD5('abc')=900150983cd24fb0d6963f7d28e17f72
MD2('abc')=da853b0d3f88d99b30283a69e6ded6bb
Dim strDigest As String Dim lpMessage() As Byte Dim lpDigest() As Byte ' Hex <-- Hex strDigest = hashHexFromHex("616263", PKI_HASH_SHA256) ' "abc" in hex Debug.Print strDigest lpMessage = StrConv("abc", vbFromUnicode) ' "abc" in a byte array ' Hex <-- Bytes strDigest = hashHexFromBytes(lpMessage, PKI_HASH_SHA256) Debug.Print strDigest ' Bytes <-- Bytes lpDigest = hashBytes(lpMessage, PKI_HASH_SHA256) Debug.Print cnvHexStrFromBytes(lpDigest) ' Hex <-- File strDigest = hashHexFromFile("abc.txt", PKI_HASH_SHA256) ' "abc" in a text file Debug.Print strDigest ' Bytes <-- File lpDigest = hashFile("abc.txt", PKI_HASH_SHA256) Debug.Print cnvHexStrFromBytes(lpDigest) Debug.Print "OK=" & "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"
Dim strData As String Dim strDigest As String ' Our original string data strData = "Estándares de Electrónica de México para mañana" ' Compute SHA-1 hash over UTF-8 encoded byte array strDigest = hashHexFromBytes(cnvUTF8BytesFromLatin1(strData), PKI_HASH_SHA1) Debug.Print "Digest=" & strDigest
Creates a message digest hash in hexadecimal format for a file. The hash algorithm to use is passed in the options parameter.
Public Declare Function HASH_HexFromFile Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nOutChars As Long, ByVal strFileName As String,
ByVal nOptions As Long) As Long
nRet = HASH_HexFromFile(strOutput, nOutChars, strFileName, nOptions)
long __stdcall HASH_HexFromFile(char *szOutput, long nOutChars, const char *szFileName, long nOptions);
RIPEMD160(SHA256(m))HASH(HASH(m))If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function hashHexFromFile (szFileName As String, nOptions As Long) As String
Hash.HexFromFile Method
Hash.HexFromTextFile Method
static std::string dipki::Hash::HexFromFile (const std::string &fileName, Alg alg=Alg::Sha1, FileMode mode=FileMode::Binary)
static Hash.hex_from_file(filename, alg=Alg.SHA1)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The maximum number of output characters will be PKI_MAX_HASH_CHARS (C/C++ users add one).
The final digest will be truncated to the specified length if less than the expected size.
Add the option PKI_HASH_MODE_TEXT to work in "text" mode where CR-LF pairs are treated
as a single newline (LF) character.
(This option is provided if you need to pass hash digests of text files between Windows and Unix systems.)
The default mode is "binary" where each byte is treated individually.
Only ANSI characters are supported in file names and paths.
Dim nRet As Long Dim sDigest As String Dim sFileName As String ' File to be hashed contains a total of 13 bytes: "hello world" plus CR-LF ' 68 65 6c 6c 6f 20 77 6f 72 6c 64 0d 0a hello world.. sFileName = "hello.txt" ' Pre-dimension digest string sDigest = String(PKI_MAX_HASH_CHARS, " ") ' Create default hash (SHA1) in binary mode nRet = HASH_HexFromFile(sDigest, Len(sDigest), sFileName, 0) Debug.Print nRet, Left(sDigest, nRet) ' Use SHA1 in "text" mode nRet = HASH_HexFromFile(sDigest, Len(sDigest), sFileName, PKI_HASH_MODE_TEXT) Debug.Print nRet, Left(sDigest, nRet) ' Use MD5 nRet = HASH_HexFromFile(sDigest, Len(sDigest), sFileName, PKI_HASH_MD5) Debug.Print nRet, Left(sDigest, nRet) ' Use MD5 in "text" mode nRet = HASH_HexFromFile(sDigest, Len(sDigest), sFileName, PKI_HASH_MD5 Or PKI_HASH_MODE_TEXT) Debug.Print nRet, Left(sDigest, nRet)
This should produce the following output:
40 88a5b867c3d110207786e66523cd1e4a484da697 40 22596363b3de40b06f981fb85d82312e8c0ed511 32 a0f2a3c1dcd5b1cac71bf0c03f2ff1bd 32 6f5902ac237024bdd0c176cb93063dc4
Dim strDigest As String Dim lpMessage() As Byte Dim lpDigest() As Byte ' Hex <-- Hex strDigest = hashHexFromHex("616263", PKI_HASH_SHA256) ' "abc" in hex Debug.Print strDigest lpMessage = StrConv("abc", vbFromUnicode) ' "abc" in a byte array ' Hex <-- Bytes strDigest = hashHexFromBytes(lpMessage, PKI_HASH_SHA256) Debug.Print strDigest ' Bytes <-- Bytes lpDigest = hashBytes(lpMessage, PKI_HASH_SHA256) Debug.Print cnvHexStrFromBytes(lpDigest) ' Hex <-- File strDigest = hashHexFromFile("abc.txt", PKI_HASH_SHA256) ' "abc" in a text file Debug.Print strDigest ' Bytes <-- File lpDigest = hashFile("abc.txt", PKI_HASH_SHA256) Debug.Print cnvHexStrFromBytes(lpDigest) Debug.Print "OK=" & "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"
Creates a message digest hash in hexadecimal format from data in a hexadecimal-encoded string. The hash algorithm to use is passed in the options parameter.
Public Declare Function HASH_HexFromHex Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nMaxChars As Long, ByVal strMsgHex As String, ByVal nOptions As Long) As Long
nRet = HASH_HexFromHex(strOutput, nMaxChars, strMsgHex, nOptions)
long __stdcall HASH_HexFromHex(char *szOutput, long nOutChars, const char *szMsgHex, long nOptions);
RIPEMD160(SHA256(m))HASH(HASH(m))If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function hashHexFromHex (szMsgHex As String, nOptions As Long) As String
static std::string dipki::Hash::HexFromHex (const std::string &dataHex, Alg alg=Alg::Sha1)
static Hash.hex_from_hex(datahex, alg=Alg.SHA1)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The maximum number of output characters is PKI_MAX_HASH_CHARS (C/C++ users add one).
The final digest will be truncated to the specified length if less than the expected size.
Valid input hex digits are [0-9A-Fa-f]. The output is always in lower-case letters.
Dim strDigest As String Dim nRet As Long Dim strData As String ' Compute SHA-1("abc") strDigest = String(PKI_SHA1_CHARS, " ") strData = "616263" nRet = HASH_HexFromHex(strDigest, Len(strDigest), strData, PKI_HASH_SHA1) Debug.Print strDigest ' Compute SHA-224("abc") strDigest = String(PKI_SHA224_CHARS, " ") strData = "616263" nRet = HASH_HexFromHex(strDigest, Len(strDigest), strData, PKI_HASH_SHA224) Debug.Print strDigest
This should produce the following output:
a9993e364706816aba3e25717850c26c9cd0d89d 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7
Dim strDigest As String Dim lpMessage() As Byte Dim lpDigest() As Byte ' Hex <-- Hex strDigest = hashHexFromHex("616263", PKI_HASH_SHA256) ' "abc" in hex Debug.Print strDigest lpMessage = StrConv("abc", vbFromUnicode) ' "abc" in a byte array ' Hex <-- Bytes strDigest = hashHexFromBytes(lpMessage, PKI_HASH_SHA256) Debug.Print strDigest ' Bytes <-- Bytes lpDigest = hashBytes(lpMessage, PKI_HASH_SHA256) Debug.Print cnvHexStrFromBytes(lpDigest) ' Hex <-- File strDigest = hashHexFromFile("abc.txt", PKI_HASH_SHA256) ' "abc" in a text file Debug.Print strDigest ' Bytes <-- File lpDigest = hashFile("abc.txt", PKI_HASH_SHA256) Debug.Print cnvHexStrFromBytes(lpDigest) Debug.Print "OK=" & "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"
Return length of message digest output in bytes.
Public Declare Function HASH_Length Lib "diCrPKI.dll" (ByVal nAlgId As Long) As Long
nRet = HASH_Length(nAlgId)
long __stdcall HASH_Length(long nAlgId);
RIPEMD160(SHA256(m))Length of the hash function output in bytes; else a negative error code.
Public Function hashLength (nAlgId As Long) As Long
static int dipki::Hash::Length (Alg alg)
static Hash.length(alg)
[New in v20.5]
Debug.Print Hash_Length(PKI_HASH_SHA512)
' 64
Debug.Print hashLength(PKI_HASH_BTC160)
' 20
Creates a keyed-hash based message authentication code (HMAC) as a byte array from byte data. The hash algorithm to use is passed in the options parameter.
Public Declare Function HMAC_Bytes Lib "diCrPKI.dll"
(ByRef lpDigest As Byte, ByVal nDigLen As Long, ByRef lpMessage As Byte,
ByVal nMsgLen As Long, ByRef lpKey As Byte, ByVal nKeyLen As Long, ByVal nOptions As Long) As Long
nRet = HMAC_Bytes(lpDigest(0), nDigLen, lpMessage(0), nMsgLen, lpKey(0), nKeyLen, nOptions) ' Note the "(0)" after the byte array parameters
long __stdcall HMAC_Bytes(unsigned char *lpOutput, long nOutBytes, const void *lpMessage, long nMsgLen, const void *lpKey, long nKeyLen, long nOptions);
If successful, the return value is the number of bytes in the output array; otherwise it returns a negative error code.
Public Function hmacBytes (lpMessage() As Byte, lpKey() As Byte, nOptions As Long) As Byte()
static bvec_t dipki::Hmac::Bytes (const bvec_t &data, const bvec_t &key, Alg alg=Alg::Sha1)
static Hmac.data(data, key, alg=Alg.SHA1)
Specify a zero nDigLen parameter to find out the required length of the output array,
or use the appropriate PKI_XXX_BYTES constant.
The maximum possible length is PKI_MAX_HASH_BYTES.
The final digest will be truncated to the specified length if less than the expected size.
MD2 is not available with the HMAC functions.
Dim abData() As Byte Dim abKey() As Byte Dim nDataLen As Long Dim nKeyLen As Long Dim abDigest() As Byte Dim nDigLen As Long Dim nRet As Long Dim i As Long ' Test case 4 from RFC 2202 and RFC 4231 ' key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819 ' key_len 25 ' data = 0xcd repeated 50 times ' data_len = 50 nKeyLen = 25 ReDim abKey(nKeyLen - 1) For i = 0 To nKeyLen - 1 abKey(i) = CByte(i + 1) Next Debug.Print "Key=" & cnvHexStrFromBytes(abKey) nDataLen = 50 ReDim abData(nDataLen - 1) For i = 0 To nDataLen - 1 abData(i) = &HCD Next ' Compute default HMAC (HMAC-SHA-1) nDigLen = PKI_SHA1_BYTES ReDim abDigest(nDigLen - 1) nRet = HMAC_Bytes(abDigest(0), nDigLen, abData(0), nDataLen, abKey(0), nKeyLen, PKI_HASH_SHA1) If nRet <= 0 Then Exit Sub ' ERROR Debug.Print "HMAC-SHA-1 =" & cnvHexStrFromBytes(abDigest) Debug.Print "CORRECT =" & "4c9007f4026250c6bc8414f9bf50c86c2d7235da" ' Compute HMAC-MD5 nDigLen = PKI_MD5_BYTES ReDim abDigest(nDigLen - 1) nRet = HMAC_Bytes(abDigest(0), nDigLen, abData(0), nDataLen, abKey(0), nKeyLen, PKI_HASH_MD5) If nRet <= 0 Then Exit Sub ' ERROR Debug.Print "HMAC-MD5 =" & cnvHexStrFromBytes(abDigest) Debug.Print "CORRECT =" & "697eaf0aca3a3aea3a75164746ffaa79" ' Compute HMAC-SHA-256 nDigLen = PKI_SHA256_BYTES ReDim abDigest(nDigLen - 1) nRet = HMAC_Bytes(abDigest(0), nDigLen, abData(0), nDataLen, abKey(0), nKeyLen, PKI_HASH_SHA256) If nRet <= 0 Then Exit Sub ' ERROR Debug.Print "HMAC-SHA-256=" & cnvHexStrFromBytes(abDigest) Debug.Print "CORRECT =" & "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"
The above example should produce the following output:
Key=0102030405060708090A0B0C0D0E0F10111213141516171819 HMAC-SHA-1 =4C9007F4026250C6BC8414F9BF50C86C2D7235DA CORRECT =4c9007f4026250c6bc8414f9bf50c86c2d7235da HMAC-MD5 =697EAF0ACA3A3AEA3A75164746FFAA79 CORRECT =697eaf0aca3a3aea3a75164746ffaa79 HMAC-SHA-256=82558A389A443C0EA4CC819899F2083A85F0FAA3E578F8077A2E3FF46729665B CORRECT =82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b
Dim strDigest As String
Dim lpMessage() As Byte
Dim lpDigest() As Byte
Dim lpKey() As Byte
lpKey = cnvBytesFromHexStr("0102030405060708090a0b0c0d0e0f10111213141516171819")
lpDigest = hmacBytes(lpMessage, lpKey, PKI_HASH_SHA256)
Debug.Print cnvHexStrFromBytes(lpDigest)
lpDigest = hmacBytes(lpMessage, lpKey, PKI_HASH_SHA256)
Debug.Print cnvHexStrFromBytes(lpDigest)
strDigest = hmacHexFromBytes(lpMessage, lpKey, PKI_HASH_SHA256)
Debug.Print strDigest
strDigest = hmacHexFromBytes(lpMessage, lpKey, PKI_HASH_SHA512)
Debug.Print strDigest
strDigest = hmacHexFromBytes(lpMessage, lpKey, PKI_HASH_SHA512)
Debug.Print strDigest
Dim lpData() As Byte Dim lpKey() As Byte Dim lpDigest() As Byte Dim strDigest As String ' Test case 4 from RFC 2202 and RFC 4231 lpKey = cnvBytesFromHexStr("0102030405060708090a0b0c0d0e0f10111213141516171819") ' data = 0xcd repeated 50 times lpData = cnvBytesFromHexStr("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" & _ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd") ' Bytes <-- Bytes lpDigest = hmacBytes(lpData, lpKey, PKI_HASH_SHA256) Debug.Print "HMAC-SHA-256=" & cnvHexStrFromBytes(lpDigest) Debug.Print "CORRECT =82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b" ' Hex <-- Bytes strDigest = hmacHexFromBytes(lpData, lpKey, PKI_HASH_SHA256) Debug.Print "HMAC-SHA-256=" & strDigest ' Hex <-- Hex ' Test case 1 from RFC 2202 and RFC 4231 ' Data = "Hi There" strDigest = hmacHexFromHex("4869205468657265", "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", PKI_HASH_SHA256) Debug.Print "HMAC-SHA-256=" & strDigest Debug.Print "CORRECT =b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"
HMAC_HexFromBytes HMAC_HexFromHex
Creates a keyed-hash based message authentication code (HMAC) in hexadecimal format from byte data. The hash algorithm to use is passed in the options parameter.
Public Declare Function HMAC_HexFromBytes Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nOutChars As Long, ByRef lpMessage As Byte,
ByVal nMsgLen As Long, ByRef lpKey As Byte, ByVal nKeyLen As Long, ByVal nOptions As Long) As Long
nRet = HMAC_HexFromBytes(strOutput, nOutChars, lpMessage(0), nMsgLen, lpKey(0), nKeyLen, nOptions)
long __stdcall HMAC_HexFromBytes(char *szOutput, long nOutChars, const void *lpMessage, long nMsgLen, const void *lpKey, long nKeyLen, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function hmacHexFromBytes (lpMessage() As Byte, lpKey() As Byte, nOptions As Long) As String
static std::string dipki::Hmac::HexFromBytes (const bvec_t &data, const bvec_t &key, Alg alg=Alg::Sha1)
static Hmac.hex_from_data(data, key, alg=Alg.SHA1)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The maximum number of output characters is PKI_MAX_HASH_CHARS (C/C++ users add one).
C/C++ users should add one to this value when allocating memory.
The final digest will be truncated to the specified length if less than the expected size.
MD2 is not available with the HMAC functions.
Dim strData As String Dim strKey As String Dim abData() As Byte Dim abKey() As Byte Dim nDataLen As Long Dim nKeyLen As Long Dim strDigest As String Dim nRet As Long ' Test case 2 from RFC 2202 and RFC 4231 strData = "what do ya want for nothing?" strKey = "Jefe" ' Convert message and key into Byte format abData = StrConv(strData, vbFromUnicode) abKey = StrConv(strKey, vbFromUnicode) nDataLen = UBound(abData) - LBound(abData) + 1 nKeyLen = UBound(abKey) - LBound(abKey) + 1 ' Dimension the output string to receive the digest strDigest = String(PKI_MAX_HASH_CHARS, " ") ' Compute default HMAC (HMAC-SHA-1) nRet = HMAC_HexFromBytes(strDigest, Len(strDigest), abData(0), nDataLen, abKey(0), nKeyLen, 0) If nRet <= 0 Then Exit Sub ' ERROR strDigest = Left(strDigest, nRet) Debug.Print "HMAC-SHA-1 =" & strDigest Debug.Print "CORRECT =" & "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79" ' Compute HMAC-MD5 strDigest = String(PKI_MAX_HASH_CHARS, " ") nRet = HMAC_HexFromBytes(strDigest, Len(strDigest), abData(0), nDataLen, abKey(0), nKeyLen, PKI_HASH_MD5) If nRet <= 0 Then Exit Sub ' ERROR strDigest = Left(strDigest, nRet) Debug.Print "HMAC-MD5 =" & strDigest Debug.Print "CORRECT =" & "750c783e6ab0b503eaa86e310a5db738" ' Compute HMAC-SHA-256 strDigest = String(PKI_MAX_HASH_CHARS, " ") nRet = HMAC_HexFromBytes(strDigest, Len(strDigest), abData(0), nDataLen, abKey(0), nKeyLen, PKI_HASH_SHA256) If nRet <= 0 Then Exit Sub ' ERROR strDigest = Left(strDigest, nRet) Debug.Print "HMAC-SHA-256=" & strDigest Debug.Print "CORRECT =" & "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843" ' Compute HMAC-SHA-512 strDigest = String(PKI_MAX_HASH_CHARS, " ") nRet = HMAC_HexFromBytes(strDigest, Len(strDigest), abData(0), nDataLen, abKey(0), nKeyLen, PKI_HASH_SHA512) If nRet <= 0 Then Exit Sub ' ERROR strDigest = Left(strDigest, nRet) Debug.Print "HMAC-SHA-512=" & strDigest Debug.Print "CORRECT =" _ & "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea250554" _ & "9758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737" _
The above example should produce the following output:
HMAC-SHA-1 =effcdf6ae5eb2fa2d27416d5f184df9c259a7c79 CORRECT =effcdf6ae5eb2fa2d27416d5f184df9c259a7c79 HMAC-MD5 =750c783e6ab0b503eaa86e310a5db738 CORRECT =750c783e6ab0b503eaa86e310a5db738 HMAC-SHA-256=5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843 CORRECT =5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843 HMAC-SHA-512=164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea250554 9758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737 CORRECT =164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea250554 9758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737
Dim strDigest As String
Dim lpMessage() As Byte
Dim lpDigest() As Byte
Dim lpKey() As Byte
lpKey = cnvBytesFromHexStr("0102030405060708090a0b0c0d0e0f10111213141516171819")
lpDigest = hmacBytes(lpMessage, lpKey, PKI_HASH_SHA256)
Debug.Print cnvHexStrFromBytes(lpDigest)
lpDigest = hmacBytes(lpMessage, lpKey, PKI_HASH_SHA256)
Debug.Print cnvHexStrFromBytes(lpDigest)
strDigest = hmacHexFromBytes(lpMessage, lpKey, PKI_HASH_SHA256)
Debug.Print strDigest
strDigest = hmacHexFromBytes(lpMessage, lpKey, PKI_HASH_SHA512)
Debug.Print strDigest
strDigest = hmacHexFromBytes(lpMessage, lpKey, PKI_HASH_SHA512)
Debug.Print strDigest
Creates a keyed-hash based message authentication code (HMAC) in hexadecimal format from data in hexadecimal-encoded strings. The hash algorithm to use is passed in the options parameter.
Public Declare Function HMAC_HexFromHex Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nOutChars As Long,
ByVal strMsgHex As String, ByVal strKeyHex As String, ByVal nOptions As Long) As Long
nRet = HMAC_HexFromHex(strOutput, nOutChars, strMsgHex, strKeyHex, nOptions)
long __stdcall HMAC_HexFromHex(char *szOutput, long nOutChars, const char *szMsgHex, const char *szKeyHex, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function hmacHexFromHex (szMsgHex As String, szKeyHex As String, nOptions As Long) As String
static std::string dipki::Hmac::HexFromHex (const std::string &dataHex, const std::string &keyHex, Alg alg=Alg::Sha1)
static Hmac.hex_from_hex(datahex, keyhex, alg=Alg.SHA1)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The maximum number of output characters is PKI_MAX_HASH_CHARS (C/C++ users add one).
C/C++ users should add one to this value when allocating memory.
The final digest will be truncated to the specified length if less than the expected size.
MD2 is not available with the HMAC functions.
Note the order of parameters here (data, key) is different from the usual order HMAC(key, text).
Dim strDigest As String Dim nRet As Long Dim strData As String Dim strKey As String ' Ref: RFC 2202 and RFC 4231 ' Test Case 1 ' Key = 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b ' 0b0b0b0b (20 bytes) ' Data = 4869205468657265 ("Hi There") ' Compute HMAC-SHA-1 strDigest = String(PKI_SHA1_CHARS, " ") strData = "4869205468657265" strKey = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b" nRet = HMAC_HexFromHex(strDigest, Len(strDigest), strData, strKey, PKI_HASH_SHA1) Debug.Print strDigest ' Compute HMAC-SHA-256 strDigest = String(PKI_SHA256_CHARS, " ") nRet = HMAC_HexFromHex(strDigest, Len(strDigest), strData, strKey, PKI_HASH_SHA256) Debug.Print strDigest
The above example should produce the following output:
b617318655057264e28bc0b6fb378c8ef146be00 b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7
Dim lpData() As Byte Dim lpKey() As Byte Dim lpDigest() As Byte Dim strDigest As String ' Test case 4 from RFC 2202 and RFC 4231 lpKey = cnvBytesFromHexStr("0102030405060708090a0b0c0d0e0f10111213141516171819") ' data = 0xcd repeated 50 times lpData = cnvBytesFromHexStr("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" & _ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd") ' Bytes <-- Bytes lpDigest = hmacBytes(lpData, lpKey, PKI_HASH_SHA256) Debug.Print "HMAC-SHA-256=" & cnvHexStrFromBytes(lpDigest) Debug.Print "CORRECT =82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b" ' Hex <-- Bytes strDigest = hmacHexFromBytes(lpData, lpKey, PKI_HASH_SHA256) Debug.Print "HMAC-SHA-256=" & strDigest ' Hex <-- Hex ' Test case 1 from RFC 2202 and RFC 4231 ' Data = "Hi There" strDigest = hmacHexFromHex("4869205468657265", "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", PKI_HASH_SHA256) Debug.Print "HMAC-SHA-256=" & strDigest Debug.Print "CORRECT =b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"
Derive an EC private key in a deterministic manner from input keying material using the DeriveKeyPair algorithm in RFC9180.
Public Declare Function HPKE_DerivePrivateKey Lib "diCrPKI.dll" (ByVal szOutput As String, ByVal nOutChars As Long, ByRef lpIkm As Byte, ByVal nIkmLen As Long, ByVal szCurveName As String, ByVal szParams As String, ByVal nOptions As Long) As Long
nRet = HPKE_DerivePrivateKey(szOutput, nOutChars, lpIkm(0), nIkmLen, szCurveName,, szParams, nOptions) ' Note the "(0)" after the byte array parameters
long __stdcall HPKE_DerivePrivateKey(char *szOutput, long nOutChars, const unsigned char *lpIkm, long nIkmLen, const char *szCurveName, const char *szParams, long nOptions);
"P-256" |
"P-384" |
"P-521" |
"X25519" |
"X448"
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function hpkeDerivePrivateKey (lpIkm() As Byte, szCurveName As String, Optional nOptions As Long = 0) As String
static std::string dipki::Hpke::DerivePrivateKey (const bvec_t &ikm, CurveName curve, OutputOpts opts=OutputOpts::Default)
static Hpke.derive_private_key(ikm, curveName, opts=0)
By default the key is output as an ephemeral "internal" key string, which can be used directly with
ECC_SaveKey,
ECC_SaveEncKey,
ECC_PublicKeyFromPrivate,
ECC_DHSharedSecret and
ECC_QueryKey.
If nOptions is set to PKI_ENCODE_HEX then the key is output in serialized hexadecimal form in the same manner as the test vectors in [RFC9180]
(without the clamping).
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
This function derives an ECDH private key in the deterministic manner described in [RFC9180] using user-provided input key material (ikm). There is very, very small chance that a valid key cannot be generated from the ikm; in which case the function will return a negative KEYGEN_FAILED_ERROR error code.
The input key material must have length in bytes at least as long as the key to be produced (Nsk) or a BAD_LENGTH_ERROR error code will be returned. The values of Nsk (the length in bytes of a Diffie-Hellman private key) for the supported EC curves are as follows:
| EC curve group | Nsk |
|---|---|
| P-256 | 32 |
| P-384 | 48 |
| P-521 | 66 |
| X25519 | 32 |
| X448 | 56 |
The KDF to be used is fixed by the EC curve group. See Hybrid Public Key Encryption (HPKE).
Dim ikmhex As String Dim skokhex As String Dim pkokhex As String Dim skhex As String Dim pkhex As String Dim prikeystr As String Debug.Print "TESTING HPKE DERIVEPRIVATEKEY..." Debug.Print "RFC9180 A.1. DHKEM(X25519, HKDF-SHA256)" ikmhex = "7268600d403fce431561aef583ee1613527cff655c1343f29812e66706df3234" skokhex = "52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736" pkokhex = "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431" ' A. Derive private key in hex format skhex = hpkeDerivePrivateKey(cnvFromHex(ikmhex), "X25519", PKI_ENCODE_HEX) Debug.Print "skEm: " & skhex ' B. Derive key in ephemeral internal private key format (NB different each time) prikeystr = hpkeDerivePrivateKey(cnvFromHex(ikmhex), "X25519") ' C. Get public key in hex format from internal key string pkhex = eccQueryKey(prikeystr, "publicKey") Debug.Print "pkEm: " & pkhex
skEm: 52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736 pkEm: 37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431
Compute the output of the LabeledExpand function as defined in RFC9180.
Public Declare Function HPKE_LabeledExpand Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpPrk As Byte, ByVal nPrkLen As Long, ByVal szLabel As String, ByRef lpInfo As Byte, ByVal nInfoLen As Long, ByVal szCurveName As String, ByVal strParams As String, ByVal nOptions As Long) As Long
nRet = HPKE_LabeledExpand(lpOutput(0), nOutBytes, lpPrk(0), nPrkLen, szLabel, lpInfo(0), nInfoLen, szCurveName, szParams, nOptions) ' Note the "(0)" after the byte array parameters
long __stdcall HPKE_LabeledExpand(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpPrk, long nPrkLen, const char *szLabel, const unsigned char *lpInfo, long nInfoLen,
const char *szCurveName, const char *szParams, long nOptions);
"P-256" |
"P-384" |
"P-521" |
"X25519" |
"X448"
If successful, the return value is zero; otherwise it returns a negative error code.
Public Function hpkeLabeledExpand (nBytes As Long, lpPrk() As Byte, szLabel As String, lpInfo() As Byte, szCurveName As String, Optional nOptions As Long = 0) As Byte()
static bvec_t dipki::Hpke::LabeledExpand (int numBytes, const bvec_t &prk, std::string label, const bvec_t &info, CurveName curve, AeadAlg aeadAlg=AeadAlg::None)
static Hpke.labeled_expand(numbytes, prk, label, info, curveName, aeadalg=AeadAlg.NONE)
The output buffer for the output keying material lpOutput must exist and must have been dimensioned to at least the required length given in nOutBytes, which must be a positive number. Note that the return value on success is zero.
The LabeledExpand function is defined in section 4 of [RFC9180]. It uses the "expand" stage of the HKDF function [RFC5869].
Because this is a standalone function with no context, the ECDH curve group used in the scheme must be specified. This automatically fixes the KDF and associated HMAC algorithm to be used as per Table 2 of [RFC9180]. In the case where the KDF is being used inside a KEM algorithm, the AEAD algorithm is not used and nOptions must be set to zero (0). In the other case where the KDF is being used in the remainder of the HPKE scheme, an explicit AEAD algorithm must be specified in nOptions. For more details see Hybrid Public Key Encryption (HPKE).
Dim lpKey() As Byte Dim lpPrk() As Byte Dim lpInfo() As Byte Dim Nk As Long Debug.Print "RFC9180 Appendix A.1 DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM" Debug.Print "key = LabeledExpand(secret, 'key', key_schedule_context, Nk)" Nk = 16 lpPrk = cnvFromHex("12fff91991e93b48de37e7daddb52981084bd8aa64289c3788471d9a9712f397") lpInfo = cnvFromHex("00725611c9d98c07c03f60095cd32d400d8347d45ed67097bbad50fc56da742d07cb6cffde367bb0565ba28bb02c90744a20f5ef37f30523526106f637abb05449") lpKey = hpkeLabeledExpand(Nk, lpPrk, "key", lpInfo, "X25519", PKI_AEAD_AES_128_GCM) Debug.Print "key=" & cnvToHex(lpKey) If cnvBytesLen(lpKey) = 0 Then Debug.Print errFormatErrorMessage()
key=4531685D41D65F03DC48F6B8302C05B0
Compute the output of the LabeledExtract function as defined in RFC9180.
Public Declare Function HPKE_LabeledExtract Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpSalt As Byte, ByVal nSaltLen As Long, ByVal strLabel As String, ByRef lpIkm As Byte, ByVal nIkmLen As Long, ByVal strCurveName As String, ByVal strParams As String, ByVal nOptions As Long) As Long
nRet = KDF_Bytes(lpOutput(0), nOutBytes, lpIKM(0), nIkmLen, lpInfo(0), nInfoLen, szParams, nOptions) ' Note the "(0)" after the byte array parameters
long __stdcall HPKE_LabeledExtract(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpSalt, long nSaltLen, const char *szLabel, const unsigned char *lpIkm, long nIkmLen,
const char *szCurveName, const char *szParams, long nOptions);
"P-256" |
"P-384" |
"P-521" |
"X25519" |
"X448"
If successful, the return value is the number of bytes in or required for the output; otherwise it returns a negative error code. otherwise it returns a negative error code.
Public Function hpkeLabeledExtract (lpSalt() As Byte, szLabel As String, lpIkm() As Byte, szCurveName As String, Optional nOptions As Long = 0) As Byte()
static bvec_t dipki::Hpke::LabeledExtract (const bvec_t &salt, std::string label, const bvec_t &ikm, CurveName curve, AeadAlg aeadAlg=AeadAlg::None)
static Hpke.labeled_extract(salt, label, ikm, curveName, aeadalg=AeadAlg.NONE)
The LabeledExtract function is defined in section 4 of [RFC9180]. It uses the "extract" stage of the HKDF function [RFC5869].
It outputs a fixed value of bytes equal to the length (Nh) of the underlying HMAC function used by the KDF algorithm.
Because this is a standalone function with no context, the ECDH curve group used in the scheme must be specified. This automatically fixes the KDF and associated HMAC algorithm to be used as per Table 2 of [RFC9180]. In the case where the KDF is being used inside a KEM algorithm, the AEAD algorithm is not used and nOptions must be set to zero (0). In the other case where the KDF is being used in the remainder of the HPKE scheme, an explicit AEAD algorithm must be specified in nOptions. For more details see Hybrid Public Key Encryption (HPKE).
Dim lpExtracted() As Byte Dim lpSalt() As Byte Dim lpIkm() As Byte Debug.Print "RFC9180 Appendix A.1 DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM" Debug.Print "prk = LabeledExtract('', 'dkp_prk', ikm)" lpSalt = vbNullString lpIkm = cnvFromHex("7268600d403fce431561aef583ee1613527cff655c1343f29812e66706df3234") lpExtracted = hpkeLabeledExtract(lpSalt, "dkp_prk", lpIkm, "X25519") Debug.Print "prk=" & cnvToHex(lpExtracted) If cnvBytesLen(lpExtracted) = 0 Then Debug.Print errFormatErrorMessage()
prk=7B8BFE1D6F3D0CB45C585E133299C64AC998BF46CAF2DC13BA874F23413EC23A
Generate a key-encryption key (KEK) from input keying material using a key derivation function (KDF).
Public Declare Function KDF_Bytes Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpIKM As Byte, ByVal nIkmLen As Long, ByRef lpInfo As Byte, ByVal nInfoLen As Long, ByVal szParams As String, ByVal nOptions As Long) As Long
nRet = KDF_Bytes(lpOutput(0), nOutBytes, lpIKM(0), nIkmLen, lpInfo(0), nInfoLen, szParams, nOptions) ' Note the "(0)" after the byte array parameters
long __stdcall KDF_Bytes(unsigned char *lpOutput, long nOutBytes, const void *lpIKM, long nIkmLen, const void *lpInfo, long nInfoLen, const char *szParams, long nOptions);
"" for defaults.
Otherwise include a set of attribute-value pairs separated by a semi-colon ";" to set options from the following
salt=<hex-digits> to set the optional salt parameter for the HKDF algorithm encoded in hex format,
e.g. "salt=606162636465666768696a6b6c6d6e6f;" [default=no salt]
If successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function kdfBytes (nKekBytes As Long, lpIkm() As Byte, lpInfo() As Byte, Optional nOptions As Long = 0, Optional szParams As String = "") As Byte()
static bvec_t dipki::Kdf::Bytes (int dklen, const bvec_t &ikm, KdfAlg kdfAlg=KdfAlg::X963, HashAlg hashAlg=HashAlg::Sha1, const bvec_t &sharedInfo={}, const std::string ¶mString="")
static Kdf.bytes(dklen, ikm, kdfalg, hashalg=HashAlg.SHA1, sharedinfo=None, paramstring="")
The output buffer for the output key material lpOutput must exist and must have been dimensioned to at least the required length given in nOutBytes, which must be a positive number. Note that the return value on success is zero.
The ANSI-X9.63-KDF key derivation function is described in section 3.6.1 of [SEC1]. The HMAC-based Key Derivation Function (HKDF) is described in [RFC5869]. KDF2 and KDF3 are described in ANSI X9.44 [X9-44].
Dim nBytes As Long Dim lpOutput() As Byte Dim lpZZ() As Byte Dim lpInfo() As Byte Dim r As Long ' ansx963_2001.rsp ' # CAVS 12.0 ' # 'ANS X9.63-2001' information for sample ' [SHA-256] ' [shared secret length = 192] ' [SharedInfo length = 0] ' [key data length = 128] ' COUNT = 0 ' Z = 96c05619d56c328ab95fe84b18264b08725b85e33fd34f08 ' SharedInfo = ' key_data = 443024c3dae66b95e6f5670601558f71 nBytes = 128 \ 8 ReDim lpOutput(nBytes - 1) lpZZ = cnvFromHex("96c05619d56c328ab95fe84b18264b08725b85e33fd34f08") r = KDF_Bytes(lpOutput(0), nBytes, lpZZ(0), cnvBytesLen(lpZZ), ByVal 0&, 0, "", PKI_KDF_X963 Or PKI_HASH_SHA256) Debug.Print "KDF_Bytes returns " & r Debug.Print "KEK=" & cnvToHex(lpOutput) Debug.Print "OK =" & "443024c3dae66b95e6f5670601558f71" ' [RFC 5869] A.1. Test Case 1 Basic test case with SHA-256 nBytes = 42 ReDim lpOutput(nBytes - 1) lpZZ = cnvFromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") ' 22 octets lpInfo = cnvFromHex("f0f1f2f3f4f5f6f7f8f9") ' 10 octets r = KDF_Bytes(lpOutput(0), nBytes, lpZZ(0), cnvBytesLen(lpZZ), lpInfo(0), cnvBytesLen(lpInfo), "salt=000102030405060708090a0b0c", PKI_KDF_HKDF Or PKI_HASH_SHA256) Debug.Print "KDF_Bytes returns " & r Debug.Print "KEK=" & cnvToHex(lpOutput) Debug.Print "OK =" & "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"
KDF_Bytes returns 0 KEK=443024C3DAE66B95E6F5670601558F71 OK =443024c3dae66b95e6f5670601558f71 KDF_Bytes returns 0 KEK=3CB25F25FAACD57A90434F64D0362F2A2D2D0A90CF1A5A4C5DB02D56ECC4C5BF34007208D5B887185865 OK =3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865
Dim lpKEK() As Byte Dim lpZZ() As Byte Dim lpInfo() As Byte ' ansx963_2001.rsp CAVS 12.0 'ANS X9.63-2001' information for sample lpZZ = cnvFromHex("96c05619d56c328ab95fe84b18264b08725b85e33fd34f08") lpKEK = kdfBytes(128 \ 8, lpZZ, lpInfo, PKI_HASH_SHA256) Debug.Print "KEK = " & cnvHexStrFromBytes(lpKEK) Debug.Print "OK = 443024c3dae66b95e6f5670601558f71" ' [RFC 5869] A.1. Test Case 1 Basic test case with SHA-256 lpZZ = cnvFromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") lpInfo = cnvFromHex("f0f1f2f3f4f5f6f7f8f9") lpKEK = kdfBytes(42, lpZZ, lpInfo, PKI_KDF_HKDF Or PKI_HASH_SHA256, "salt=000102030405060708090a0b0c") Debug.Print "KEK = " & cnvHexStrFromBytes(lpKEK) Debug.Print "OK = 3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"
Generate a key-encryption key (KEK) for ECDH key exchange in a CMS EnvelopedData object.
Public Declare Function KDF_ForCms Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpZZ As Byte, ByVal nZzLen As Long, ByRef lpUkm As Byte, ByVal nUkmLen As Long, ByVal szParams As String, ByVal nOptions As Long) As Long
nRet = KDF_ForCms(lpOutput(0), nOutBytes, lpZZ(0), nZzLen, lpUkm(0), nUkmLen, szParams, nOptions) ' Note the "(0)" after the byte array parameters
long __stdcall KDF_ForCms(unsigned char *lpOutput, long nOutBytes, const void *lpZZ, long nZzLen, const void *lpUkm, long nUkmLen, const char *szParams, long nOptions);
cms3DESwrapaes128-wrapaes192-wrapaes256-wrapIf successful, the return value is the number of bytes in or required for the output key material; otherwise it returns a negative error code.
Public Function kdfForCms (lpZZ() As Byte, lpUkm() As Byte, Optional nOptions As Long = 0) As Byte()
static bvec_t dipki::Kdf::ForCms (const bvec_t &zz, KeyWrapAlg keyWrapAlg, KdfAlg kdfAlg=KdfAlg::X963, HashAlg hashAlg=HashAlg::Sha1, const bvec_t &ukm={})
static Kdf.for_cms(zz, keywrapalg, kdfalg=KdfAlg.X963, hashalg=HashAlg.SHA1, ukm=None)
This is a specialist function using the key definition algorithms described in [RFC5753] and [RFC8418] when used for key agreement with ECDH in a CMS EnvelopedData object using the ECC-CMS-SharedInfo structure.
Note the behaviour of this function is different from KDF_KeyBytes as the length of the output is fixed by the key wrap algorithm and is not an arbitrary number.
The function returns the number of bytes in the output key material, not zero on success.
Specify a zero nOutChars or NULL for szOutput to find the required number of bytes for the given key wrap algorithm.
The output buffer for the output key material lpOutput must have been dimensioned to at least the required length in nOutBytes.
When using ECDH with EnvelopedData, the key-encryption keys are derived using the ECC-CMS-SharedInfo type, described in section 7.2 of [RFC5753] (the SharedInfo input to the KDF is the DER-encoded ECC-CMS-SharedInfo structure). The processing of the ukm with the HKDF key derivation function is described in section 2.2 of [RFC8418] (TL;DR if provided, the ukm is included in the entityUInfo field of the ECC-CMS-SharedInfo structure and is used as the salt, otherwise no salt is provided).
Dim nBytes As Long
Dim lpOutput() As Byte
Dim lpZZ() As Byte
Dim lpUkm() As Byte
lpZZ = cnvFromHex("160E3F5588C6FB4E9CEE8BC3C1C5000AB86396468C3D1CAEC0CB6E21536B5513")
' How many bytes for specified key wrap algorithm?
nBytes = KDF_ForCms(ByVal 0&, 0, lpZZ(0), cnvBytesLen(lpZZ), ByVal 0&, 0, "", PKI_KWRAP_AES128 Or PKI_KDF_X963 Or PKI_HASH_SHA1)
Debug.Print "KDF_ForCms returns " & nBytes
Debug.Assert (nBytes > 0)
ReDim lpOutput(nBytes - 1)
nBytes = KDF_ForCms(lpOutput(0), nBytes, lpZZ(0), cnvBytesLen(lpZZ), ByVal 0&, 0, "", PKI_KWRAP_AES128 Or PKI_KDF_X963 Or PKI_HASH_SHA1)
Debug.Print "KEK=" & cnvToHex(lpOutput)
Debug.Print "OK =" & "04D616C654CDF62BB186A5A088B60FB5"
lpUkm = cnvFromHex("616263") ' "abc"
nBytes = KDF_ForCms(ByVal 0&, 0, lpZZ(0), cnvBytesLen(lpZZ), lpUkm(0), cnvBytesLen(lpUkm), "", PKI_KWRAP_AES256 Or PKI_KDF_HKDF Or PKI_HASH_SHA256)
Debug.Print "KDF_ForCms returns " & nBytes
Debug.Assert (nBytes > 0)
ReDim lpOutput(nBytes - 1)
nBytes = KDF_ForCms(lpOutput(0), nBytes, lpZZ(0), cnvBytesLen(lpZZ), lpUkm(0), cnvBytesLen(lpUkm), "", PKI_KWRAP_AES256 Or PKI_KDF_HKDF Or PKI_HASH_SHA256)
Debug.Print "KEK=" & cnvToHex(lpOutput)
Debug.Print "OK =" & "1D06D6FD5C1EBFB33CAD875E6B99781D3D750875F573C9093CECBFBA6937ACC5"
KDF_ForCms returns 16 KEK=04D616C654CDF62BB186A5A088B60FB5 OK =04D616C654CDF62BB186A5A088B60FB5 KDF_ForCms returns 32 KEK=1D06D6FD5C1EBFB33CAD875E6B99781D3D750875F573C9093CECBFBA6937ACC5 OK =1D06D6FD5C1EBFB33CAD875E6B99781D3D750875F573C9093CECBFBA6937ACC5
Dim lpKEK() As Byte
Dim lpZZ() As Byte
Dim lpUkm() As Byte
lpZZ = cnvFromHex("160E3F5588C6FB4E9CEE8BC3C1C5000AB86396468C3D1CAEC0CB6E21536B5513")
lpKEK = kdfForCms(lpZZ, lpUkm, PKI_KWRAP_AES128 Or PKI_KDF_X963 Or PKI_HASH_SHA1)
Debug.Print "KEK = " & cnvHexStrFromBytes(lpKEK)
Debug.Print "OK = 04D616C654CDF62BB186A5A088B60FB5"
lpUkm = cnvFromHex("616263") ' "abc"
lpKEK = kdfForCms(lpZZ, lpUkm, PKI_KWRAP_AES256 Or PKI_KDF_HKDF Or PKI_HASH_SHA256)
Debug.Print "KEK = " & cnvHexStrFromBytes(lpKEK)
Debug.Print "OK = 1D06D6FD5C1EBFB33CAD875E6B99781D3D750875F573C9093CECBFBA6937ACC5"
Creates an Online Certification Status Protocol (OCSP) request as a base64 string.
Public Declare Function OCSP_MakeRequest Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strIssuerCert As String, ByVal strCertFileOrSerialNum As String, ByVal strExtensions As String, ByVal nOptions As Long) As Long
nRet = OCSP_MakeRequest(strOutput, nOutChars, strIssuerCert, strCertFileOrSerialNum, strExtensions, nOptions)
long __stdcall OCSP_MakeRequest(char *szOutput, long nOutChars, const char *szIssuerCert, const char *szCertFileOrSerialNum, const char *szExtensions, long nOptions);
"" or NULL.If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function ocspMakeRequest (szIssuerCert As String, szCertFileOrSerialNum As String, nOptions As Long, Optional szExtensions As String = "") As String
static std::string dipki::Ocsp::MakeRequest (const std::string &issuerCert, const std::string &certFileOrSerialNumber, HashAlg hashAlg=HashAlg::Sha1)
static Ocsp.make_request(issuercert, certfile_or_serialnumber, hashalg=0)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The output is a base64 string suitable for an OCSP request to an Online Certificate Status Manager.
The issuer's X.509 certficate must be specified. The certificate to be checked
can either be specified directly as a filename or as a serialNumber in hexadecimal format preceded by "#x", e.g.
"#x01deadbeef".
If the latter format is used, it must be in hexadecimal format, so the serial number 10 would be passed as
"#x0a".
It is an error (NO_MATCH_ERROR) if the issuer's name of the certificate to be checked
does not match the subject name of the issuer's certificate.
The default hash algorithm is SHA-1. Most Online Certificate Status Managers should accept MD5 and SHA-1.
Other hash algorithms may not be accepted.
One way to obtain a response is to paste the URL in the address bar of a web browser to return the status information. The base64 value produced by this function should first be URL-encoded (i.e. "/" replaced by "%2F", "+" replaced by "%2B", and "=" by "%3D"). For example, typing in the Firefox browser URL box
http://ocsp.comodoca.com/MFIwUDBOMEwwSjAJBgUrDgMCGgUABBRtl6lMY2%2BiPob4twryIF%2BFfgUdvwQUK8NGq7oOyWUqRtF5R8Ri4uHa%2FLgCEQD7xyMijIyAItiFkiPe5wZg
should offer to save a file with a name like
MFIwUDBOME....
This contains the response, which is a binary file that can be examined using the
OCSP_ReadResponse() function.
This example creates an OCSP request to check our own (old but never revoked) code signing certificate file dims.cer.
This was issued by the holder of certificate in the file UTNUSERFirst-Object.cer.
Dim nChars As Long Dim strCertFile As String Dim strIssuerFile As String Dim strBuf As String strIssuerFile = "UTNUSERFirst-Object.cer" strCertFile = "dims.cer" Debug.Print "IssuerFile=" & strIssuerFile Debug.Print "CertFile=" & strCertFile ' Find required length (or error) nChars = OCSP_MakeRequest("", 0, strIssuerFile, strCertFile, "", 0) Debug.Print "OCSP_MakeRequest returns " & nChars & "(expected +ve)" If (nChars <= 0) Then Exit Sub ' ERROR strBuf = String(nChars, " ") nChars = OCSP_MakeRequest(strBuf, nChars, strIssuerFile, strCertFile, "", 0) Debug.Print "OCSPRequest=" & strBuf ' Pass a hex serial number instead of filename strCertFile = "#x 00 FB C7 23 22 8C 8C 80 22 D8 85 92 23 DE E7 06 60" Debug.Print "Cert SerialNumber=" & strCertFile nChars = OCSP_MakeRequest("", 0, strIssuerFile, strCertFile, "", 0) Debug.Print "OCSP_MakeRequest returns " & nChars & "(expected +ve)" If (nChars <= 0) Then Exit Sub ' ERROR strBuf = String(nChars, " ") nChars = OCSP_MakeRequest(strBuf, nChars, strIssuerFile, strCertFile, "", 0) Debug.Print "OCSPRequest=" & strBuf
The above example should produce the following output:
IssuerFile=UTNUSERFirst-Object.cer CertFile=dims.cer OCSP_MakeRequest returns 112(expected +ve) OCSPRequest=MFIwUDBOMEwwSjAJBgUrDgMCGgUABBRtl6lMY2+iPob4twryIF+FfgUdvwQUK8NGq7oOyWUqRtF5R8Ri4uHa/LgCEQD7xyMijIyAItiFkiPe5wZg Cert SerialNumber=#x 00 FB C7 23 22 8C 8C 80 22 D8 85 92 23 DE E7 06 60 OCSP_MakeRequest returns 112(expected +ve) OCSPRequest=MFIwUDBOMEwwSjAJBgUrDgMCGgUABBRtl6lMY2+iPob4twryIF+FfgUdvwQUK8NGq7oOyWUqRtF5R8Ri4uHa/LgCEQD7xyMijIyAItiFkiPe5wZg
Dim strOcsp As String strOcsp = ocspMakeRequest("UTNUSERFirst-Object.cer", "dims.cer", PKI_HASH_SHA1) Debug.Print strOcsp ' Pass serial number instead of filename strOcsp = ocspMakeRequest("UTNUSERFirst-Object.cer", "#x 00 FB C7 23 22 8C 8C 80 22 D8 85 92 23 DE E7 06 60", PKI_HASH_SHA1) Debug.Print strOcsp
Reads a response to an Online Certification Status Protocol (OCSP) request and outputs the main results in text form.
Public Declare Function OCSP_ReadResponse Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strResponseFile As String, ByVal strIssuerCert As String, ByVal strExtensions As String, ByVal nOptions As Long) As Long
nRet = OCSP_ReadResponse(strOutput, nOutChars, strResponseFile, strIssuerCert, strExtensions, nOptions)
long __stdcall OCSP_ReadResponse(char *szOutput, long nOutChars, const char *szResponseFile, const char *szIssuerCert, const char *szExtensions, long nOptions);
"" or NULL.If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function ocspReadResponse (szResponseFile As String, Optional szIssuerCert As String = "", Optional nOptions As Long = 0, Optional szExtensions As String = "") As String
static std::string dipki::Ocsp::ReadResponse (const std::string &responseFile, const std::string &issuerCert="")
static Ocsp.read_response(responsefile, issuercert="")
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The output is a text string outlining the main results in the response data. Typical result strings are:
Successful response: Produced at 2010-03-18T00:09:28Z CertStatus=good SerialNumber=00FBC723228C8C8022D8859223DEE70660
Successful response: Produced at 2010-03-27T12:13:11Z CertStatus=revoked at 2009-05-29T19:23:16Z SerialNumber=7FFED5D77FD1AEEC63716CA220B098A9
malformedRequest.
unauthorized.
Note that a revoked certificate will still result in a "Successful response".
The issuer's X.509 certficate szIssuerCert is optional. If provided, it will be used to check the signature on the OCSP reponse and
and an error will result if the signature is not valid.
CAUTION: For some CAs (e.g. VeriSign) the key used to sign the OCSP response is not the same as the key in the issuer's certificate,
so specifying the issuer's certificate in this case will result in a signature error.
If you can separately obtain the certificate used to sign the OCSP response, then specify this as the szIssuerCert;
otherwise leave as the empty string "".
Dim nChars As Long Dim strResponseFile As String Dim strIssuerFile As String Dim strBuf As String strResponseFile = "ocsp_response_ok_dims.dat" strIssuerFile = "UTNUSERFirst-Object.cer" Debug.Print "ResponseFile=" & strResponseFile Debug.Print "IssuerFile=" & strIssuerFile nChars = OCSP_ReadResponse("", 0, strResponseFile, strIssuerFile, "", 0) Debug.Print "OCSP_ReadResponse returns " & nChars & " (expected +ve)" If (nChars <= 0) Then Exit Sub ' ERROR strBuf = String(nChars, " ") nChars = OCSP_ReadResponse(strBuf, nChars, strResponseFile, strIssuerFile, "", 0) Debug.Print "OCSPResponse=" & strBuf
The above example using a response received from ocsp.usertrust.com for our own (old but never revoked) code signing certificate produced the following output:
ResponseFile=ocsp_response_ok_dims.dat IssuerFile=UTNUSERFirst-Object.cer OCSP_ReadResponse returns 120 (expected +ve) OCSPResponse=Successful response: Produced at 2010-03-18T00:09:28Z CertStatus=good SerialNumber=00FBC723228C8C8022D8859223DEE70660
Dim strBuf As String
strBuf = ocspReadResponse("ocsp_response_ok_dims.dat", "UTNUSERFirst-Object.cer")
Debug.Print strBuf
Creates an input block suitably padded for encryption by a block cipher in ECB or CBC mode.
Public Declare Function PAD_BytesBlock Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutputLen As Long, ByRef lpInput As Byte, ByVal nInputLen As Long, ByVal nBlockLen As Long, ByVal nOptions As Long) As Long
nRet = PAD_BytesBlock(lpOutput(0), nOutputLen, lpInput(0), nInputLen, nBlockLen, nOptions) ' Note the "(0)" after the byte array parameters
long __stdcall PAD_BytesBlock(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpInput, long nInputLen, long nBlkLen, long nOptions);
If successful, the return value is the number of bytes in the output; otherwise it returns a negative error code.
Public Function padBytesBlock (lpInput() As Byte, nBlkLen As Long, Optional nOptions As Long = 0) As Byte()
static bvec_t dipki::Cipher::Pad (const bvec_t &input, Alg alg, Padding pad=Padding::Pkcs5)
static Cipher.pad(data, alg, pad=Pad.PKCS5)
The output will be padded according to the convention specified.
If nOutBytes is set to zero or lpOutput set to 0 (or NULL in C or ByVal 0& in VBA)
then the required number of bytes will be returned. The output is always longer than the input.
Only block lengths of 8 or 16 bytes are supported.
Note the test when unpadding to cope with a zero-length byte array.
Dim abInput() As Byte Dim abOutput() As Byte Dim nOutputLen As Long Dim nInputLen As Long Dim nBlockLen As Long Dim i As Long ' Prepare test input 5 bytes long nInputLen = 5 ReDim abInput(nInputLen - 1) For i = 0 To nInputLen - 1 abInput(i) = &HFF Next Debug.Print "Input data=0x" & cnvHexStrFromBytes(abInput) ' Find out the required length nBlockLen = 8 nOutputLen = PAD_BytesBlock(vbNull, 0, abInput(0), nInputLen, nBlockLen, 0) Debug.Print "Required length is " & nOutputLen & " bytes" ' Check for error If (nOutputLen <= 0) Then Exit Function ' Pre-dimension output ReDim abOutput(nOutputLen - 1) nOutputLen = PAD_BytesBlock(abOutput(0), nOutputLen, abInput(0), nInputLen, nBlockLen, 0) Debug.Print "Padded data=0x" & cnvHexStrFromBytes(abOutput) ' Now set input as padded output and remove padding abInput = abOutput nInputLen = nOutputLen ' Remove padding... ' No need to query for length because we know the output will be shorter than input ' so make sure output is as long as the input nOutputLen = nInputLen ReDim abOutput(nOutputLen - 1) nOutputLen = PAD_UnpadBytes(abOutput(0), nOutputLen, abInput(0), nInputLen, nBlockLen, 0) Debug.Print "Unpadded length is " & nOutputLen & " bytes" ' Check for error If (nOutputLen < 0) Then Exit Function ' Truncate the output to the correct length If nOutputLen > 0 Then ReDim Preserve abOutput(nOutputLen - 1) Else ' Catch zero-length output abOutput = vbNullString End If Debug.Print "Unpadded data=0x" & cnvHexStrFromBytes(abOutput)
This should result in output as follows:
Input data=0xFFFFFFFFFF Required length is 8 bytes Padded data=0xFFFFFFFFFF030303 Unpadded length is 5 bytes Unpadded data=0xFFFFFFFFFF
Dim lpInput() As Byte
Dim lpBlock() As Byte
Dim lpUnpadded() As Byte
lpInput = cnvBytesFromHexStr("FDFDFDFDFD")
Debug.Print "Input data = 0x" & cnvHexStrFromBytes(lpInput)
lpBlock = padBytesBlock(lpInput, 8, 0)
Debug.Print "Padded data = 0x" & cnvHexStrFromBytes(lpBlock)
' Unpad
lpUnpadded = padUnpadBytes(lpBlock, 8, 0)
Debug.Print "Unpadded data = 0x" & cnvHexStrFromBytes(lpUnpadded)
' Special corner case - output is the empty string
lpBlock = cnvBytesFromHexStr("0808080808080808")
Debug.Print "Padded data = 0x" & cnvHexStrFromBytes(lpBlock)
lpUnpadded = padUnpadBytes(lpBlock, 8, 0)
Debug.Print "Unpadded data = 0x" & cnvHexStrFromBytes(lpUnpadded)
PAD_UnpadBytes
PAD_HexBlock
PAD_UnpadHex
Creates a hex-encoded input block suitably padded for encryption by a block cipher in ECB or CBC mode.
Public Declare Function PAD_HexBlock Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nMaxChars As Long, ByVal strInputHex As String, ByVal nBlockLen As Long, ByVal nOptions As Long) As Long
nRet = PAD_HexBlock(strOutput, nMaxChars, strInput, nBlockLen, nOptions)
long __stdcall PAD_HexBlock(char *szOutput, long nOutChars, const char *szInput, long nBlkLen, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function padHexBlock (szInput As String, nBlkLen As Long, Optional nOptions As Long = 0) As String
Use the method associated with the relevant encryption algorithm class:
Cipher.Pad Method (String, CipherAlgorithm, Padding)
static Cipher.pad_hex(datahex, alg, pad=Pad.PKCS5)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The output will be padded according to the convention specified in nOptions. The output is always longer than the input. Only block lengths of 8 or 16 bytes are supported.
Dim strInputHex As String Dim strOutputHex As String Dim nOutChars As Long Dim nBlockLen As Long Dim i As Long ' Prepare test input 5 bytes long strInputHex = "FFFFFFFFFF" Debug.Print "Input data='" & strInputHex & "'" ' Find out the required number of characters in output nBlockLen = 8 ' NB block length is in bytes nOutChars = PAD_HexBlock("", 0, strInputHex, nBlockLen, 0) Debug.Print "Required length is " & nOutChars & " characters" ' Check for error If (nOutChars <= 0) Then Exit Function ' Pre-dimension output strOutputHex = String(nOutChars, " ") nOutChars = PAD_HexBlock(strOutputHex, Len(strOutputHex), strInputHex, nBlockLen, 0) Debug.Print "Padded data='" & strOutputHex & "'" ' Now set input as padded output and remove padding strInputHex = strOutputHex ' Remove padding... ' No need to query for length because we know the output will be shorter than input ' so make sure output is as long as the input strOutputHex = String(Len(strInputHex), " ") nOutChars = PAD_UnpadHex(strOutputHex, Len(strOutputHex), strInputHex, nBlockLen, 0) Debug.Print "Unpadded length is " & nOutChars & " characters" ' Check for error If (nOutChars <= 0) Then Exit Function ' Re-dimension the output to the correct length strOutputHex = Left$(strOutputHex, nOutChars) Debug.Print "Unpadded data='" & strOutputHex & "'"
This should result in output as follows:
Input data='FFFFFFFFFF' Required length is 16 characters Padded data='FFFFFFFFFF030303' Unpadded length is 10 characters Unpadded data='FFFFFFFFFF'
Dim strInputHex As String Dim strOutputHex As String strInputHex = "FDFDFD" Debug.Print "Hex input =" & strInputHex strOutputHex = padHexBlock(strInputHex, 8, 0) Debug.Print "Padded data=" & strOutputHex Debug.Print "Unpadded =" & padUnpadHex(strOutputHex, 8, 0) strOutputHex = padHexBlock(strInputHex, 8, PKI_PAD_1ZERO) Debug.Print "Padded data=" & strOutputHex Debug.Print "Unpadded =" & padUnpadHex(strOutputHex, 8, PKI_PAD_1ZERO) strOutputHex = padHexBlock(strInputHex, 8, PKI_PAD_AX923) Debug.Print "Padded data=" & strOutputHex Debug.Print "Unpadded =" & padUnpadHex(strOutputHex, 8, PKI_PAD_AX923)
PAD_UnpadHex
PAD_BytesBlock
PAD_UnpadBytes
Removes the padding from an encryption block.
Public Declare Function PAD_UnpadBytes Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutputLen As Long, ByRef lpInput As Byte, ByVal nInputLen As Long, ByVal nBlockLen As Long, ByVal nOptions As Long) As Long
nRet = PAD_UnpadBytes(lpOutput(0), nOutputLen, lpInput(0), nInputLen, nBlockLen, nOptions) ' Note the "(0)" after the byte array parameters
long __stdcall PAD_UnpadBytes(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpInput, long nInputLen, long nBlkLen, long nOptions);
If successful, the return value is the number of bytes in the output; otherwise it returns a negative error code.
Public Function padUnpadBytes (lpInput() As Byte, nBlkLen As Long, Optional nOptions As Long = 0) As Byte()
Use the method associated with the relevant encryption algorithm class:
Cipher.Unpad Method (Byte[], CipherAlgorithm, Padding)
static bvec_t dipki::Cipher::Unpad (const bvec_t &input, Alg alg, Padding pad=Padding::Pkcs5)
static Cipher.unpad(data, alg, pad=Pad.PKCS5)
The padding is expected according to the convention specified.
If nOutBytes is set to zero or lpOutput set to 0 (or NULL in C or ByVal 0& in VBA)
then the required number of bytes will be returned. The output is always shorter than the input.
Only block lengths of 8 or 16 bytes are supported.
This example shows how to cope with a zero-length output in VBA (you can't do ReDim(nOutputLen - 1) when nOutputLen is zero).
Dim abInput() As Byte
Dim abOutput() As Byte
Dim nOutputLen As Long
Dim nInputLen As Long
Dim nBlockLen As Long
Dim i As Long
nBlockLen = 8
' Prepare test input 8 bytes long, all equal to 0x08
' (the padded block for a zero-length input)
nInputLen = nBlockLen
ReDim abInput(nInputLen - 1)
For i = 0 To nInputLen - 1
abInput(i) = CByte(nInputLen)
Next
Debug.Print "Padded data=0x(" & cnvHexStrFromBytes(abInput) & ")"
' Remove padding...
' No need to query for length because we know the output will be shorter than input
' so make sure output is as long as the input
nOutputLen = nInputLen
ReDim abOutput(nOutputLen - 1)
nOutputLen = PAD_UnpadBytes(abOutput(0), nOutputLen, abInput(0), nInputLen, nBlockLen, 0)
Debug.Print "Unpadded length is " & nOutputLen & " bytes"
' Check for error
If (nOutputLen < 0) Then Exit Function
' Truncate the output to the correct length
If nOutputLen > 0 Then
ReDim Preserve abOutput(nOutputLen - 1)
Else
' Catch zero-length output
abOutput = vbNullString
End If
Debug.Print "Unpadded data=0x(" & cnvHexStrFromBytes(abOutput) & ")"
This should result in output as follows:
Padded data=0x(0808080808080808) Unpadded length is 0 bytes Unpadded data=0x()
Dim lpInput() As Byte
Dim lpBlock() As Byte
Dim lpUnpadded() As Byte
lpInput = cnvBytesFromHexStr("FDFDFDFDFD")
Debug.Print "Input data = 0x" & cnvHexStrFromBytes(lpInput)
lpBlock = padBytesBlock(lpInput, 8, 0)
Debug.Print "Padded data = 0x" & cnvHexStrFromBytes(lpBlock)
' Unpad
lpUnpadded = padUnpadBytes(lpBlock, 8, 0)
Debug.Print "Unpadded data = 0x" & cnvHexStrFromBytes(lpUnpadded)
' Special corner case - output is the empty string
lpBlock = cnvBytesFromHexStr("0808080808080808")
Debug.Print "Padded data = 0x" & cnvHexStrFromBytes(lpBlock)
lpUnpadded = padUnpadBytes(lpBlock, 8, 0)
Debug.Print "Unpadded data = 0x" & cnvHexStrFromBytes(lpUnpadded)
PAD_BytesBlock
PAD_HexBlock
PAD_UnpadHex
Removes the padding from a hex-encoded encryption block.
Public Declare Function PAD_UnpadHex Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nMaxChars As Long, ByVal strInputHex As String, ByVal nBlockLen As Long, ByVal nOptions As Long) As Long
nRet = PAD_UnpadHex(strOutput, nMaxChars, strInput, nBlockLen, nOptions)
long __stdcall PAD_UnpadHex(char *szOutput, long nOutChars, const char *szInput, long nBlkLen, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function padUnpadHex (szInput As String, nBlkLen As Long, Optional nOptions As Long = 0) As String
Use the method associated with the relevant encryption algorithm class:
Cipher.Unpad Method (String, CipherAlgorithmPadding)
static Cipher.unpad_hex(datahex, alg, pad=Pad.PKCS5)
The padding is expected according to the convention specified in nOptions. The output is always shorter than the input. Only block lengths of 8 or 16 bytes are supported. Note that it is a valid result for szOutput to be an empty string.
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
When using the VBA wrapper function padUnpadHex and there is an error, then the input is returned unchanged. The user should check for this and signal an error.
See the VBA wrapper example below.
See the example in PAD_HexBlock.
Dim strInputHex As String Dim strOutputHex As String strInputHex = "FDFDFD" Debug.Print "Hex input =" & strInputHex strOutputHex = padHexBlock(strInputHex, 8, 0) Debug.Print "Padded data=" & strOutputHex Debug.Print "Unpadded =" & padUnpadHex(strOutputHex, 8, 0) strOutputHex = padHexBlock(strInputHex, 8, PKI_PAD_1ZERO) Debug.Print "Padded data=" & strOutputHex Debug.Print "Unpadded =" & padUnpadHex(strOutputHex, 8, PKI_PAD_1ZERO) strOutputHex = padHexBlock(strInputHex, 8, PKI_PAD_AX923) Debug.Print "Padded data=" & strOutputHex Debug.Print "Unpadded =" & padUnpadHex(strOutputHex, 8, PKI_PAD_AX923)
Dim strInputHex As String Dim strOutputHex As String strInputHex = "FFFFFFFFFF030303" Debug.Print "Hex input =" & strInputHex strOutputHex = padUnpadHex(strInputHex, PKI_BLK_TDEA_BYTES, 0) Debug.Print "Unpadded =" & strOutputHex ' Output is empty string strInputHex = "0808080808080808" Debug.Print "Hex input =" & strInputHex strOutputHex = padUnpadHex(strInputHex, PKI_BLK_TDEA_BYTES, 0) Debug.Print "Unpadded =" & strOutputHex ' Bad input data results in the same data being returned strInputHex = "FFFFFFFFFFFFFFFF" Debug.Print "Hex input =" & strInputHex strOutputHex = padUnpadHex(strInputHex, PKI_BLK_TDEA_BYTES, 0) Debug.Print "Unpadded =" & strOutputHex If Len(strOutputHex) = Len(strInputHex) Then Debug.Print "DECRYPTION ERROR" End If Debug.Assert Len(strOutputHex) = Len(strInputHex)
PAD_HexBlock
PAD_BytesBlock
PAD_UnpadBytes
Derives a key of any length from a password using the PBKDF2 algorithm from PKCS #5.
Public Declare Function PBE_Kdf2 Lib "diCrPKI.dll"
(ByRef lpDerivedKey As Byte, ByVal nKeyLen As Long,
ByRef lpPwd As Byte, ByVal nPwdLen As Long,
ByRef lpSalt As Byte, ByVal nSaltLen As Long,
ByVal nCount As Long, ByVal nOptions As Long) As Long
nRet = PBE_Kdf2(lpDerivedKey(0), nKeyLen, lpPwd(0), nPwdLen, lpSalt(0), nSaltLen, nCount, nOptions) ' Note the "(0)" after the byte array parameters
long __stdcall PBE_Kdf2(unsigned char *lpOutput, long nOutputLen, const unsigned char *lpPwd, long nPwdLen, const unsigned char *lpSalt, long nSaltLen, long nCount, long nOptions);
If successful, the return value is 0; otherwise it returns a non-zero error code.
Public Function pbeKdf2 (dkBytes As Long, lpPwd() As Byte, lpSalt() As Byte, nCount As Long, Optional nOptions As Long = 0) As Byte()
Pbe.Kdf2 Method (Int32, Byte[], Byte[], Int32, HashAlgorithm)
static bvec_t dipki::Pbe::Kdf2 (int dklen, const std::string password, const bvec_t &salt, int count, PrfAlg prfalg=PrfAlg::Hmac_Sha1)
static Pbe.kdf2(dklen, password, salt, count, prfalg=0)
The output buffer for the derived key abDerivedKey() must have been dimensioned to at least the
required length.
This example uses PBKDF2 as defined in PKCS #5 v2.0 from test vectors provided by Dr. Stephen Henson. The password is "password" (without quotes). This derived key is for the 'des-ede3-cbc' example in the test vectors and therefore needs to be 24 bytes long.
Dim abDerivedKey() As Byte
Dim nKeyLen As Long
Dim sPassword As String
Dim abPwdBytes() As Byte
Dim abSalt(7) As Byte
Dim nCount As Long
Dim nRet As Long
' Convert password String to an array of Bytes
sPassword = "password"
abPwdBytes = StrConv(sPassword, vbFromUnicode)
' Set 8-byte salt = 78 57 8E 5A 5D 63 CB 06
abSalt(0) = &H78
abSalt(1) = &H57
abSalt(2) = &H8E
abSalt(3) = &H5A
abSalt(4) = &H5D
abSalt(5) = &H63
abSalt(6) = &HCB
abSalt(7) = &H6
' Iteration count is 2048
nCount = 2048
' Pre-dimension output for derived key to required length of 24 bytes
' (Don't forget to do this)
nKeyLen = 24
ReDim abDerivedKey(nKeyLen - 1)
' Derive PBKDF2 key using function from CryptoSys
nRet = PBE_Kdf2(abDerivedKey(0), nKeyLen, _
abPwdBytes(0), Len(sPassword), abSalt(0), 8&, nCount, 0&)
' Convert bytes to hex and print
Debug.Print "Derived key = " & cnvHexStrFromBytes(abDerivedKey)
Debug.Print "Correct key = BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"
This should result in output as follows:
Derived key = BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643 Correct key = BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643
Had we specified the required key length to be 64 bytes instead of 24, we would have generated this 512-bit key:
BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643C4B150DEF7751122 4479994567F2E9B4E3BD0DF7AEDA3022B1F26051D81505C794F8940C04DF1144
This second example shows how other SHA-2 hash functions can be used.
Dim abDerivedKey() As Byte
Dim nKeyLen As Long
Dim sPassword As String
Dim abPwdBytes() As Byte
Dim abSalt(7) As Byte
Dim nSaltBytes As Long
Dim nCount As Long
Dim nRet As Long
' Convert password String to an array of Bytes
sPassword = "password"
abPwdBytes = StrConv(sPassword, vbFromUnicode)
' Set 8-byte salt = 78 57 8E 5A 5D 63 CB 06
abSalt(0) = &H78
abSalt(1) = &H57
abSalt(2) = &H8E
abSalt(3) = &H5A
abSalt(4) = &H5D
abSalt(5) = &H63
abSalt(6) = &HCB
abSalt(7) = &H6
nSaltBytes = 8
' Iteration count is 2048
nCount = 2048
' Pre-dimension output for derived key to required length of 24 bytes
' (Don't forget to do this)
nKeyLen = 24
ReDim abDerivedKey(nKeyLen - 1)
' Derive PBKDF2 key using function from CryptoSys API with default HMAC-SHA-1
nRet = PBE_Kdf2(abDerivedKey(0), nKeyLen, _
abPwdBytes(0), Len(sPassword), abSalt(0), nSaltBytes, nCount, PKI_HASH_SHA1)
' Convert bytes to hex and print
Debug.Print "Derived key {HMAC-SHA-1} = " & cnvHexStrFromBytes(abDerivedKey)
' Derive PBKDF2 key using function from CryptoSys API with HMAC-SHA-256
nRet = PBE_Kdf2(abDerivedKey(0), nKeyLen, _
abPwdBytes(0), Len(sPassword), abSalt(0), nSaltBytes, nCount, PKI_HASH_SHA256)
Debug.Print "Derived key {HMAC-SHA-256} = " & cnvHexStrFromBytes(abDerivedKey)
' Derive PBKDF2 key using function from CryptoSys API with HMAC-SHA-224
nRet = PBE_Kdf2(abDerivedKey(0), nKeyLen, _
abPwdBytes(0), Len(sPassword), abSalt(0), nSaltBytes, nCount, PKI_HASH_SHA224)
Debug.Print "Derived key {HMAC-SHA-224} = " & cnvHexStrFromBytes(abDerivedKey)
This should result in output as follows:
Derived key {HMAC-SHA-1} = BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643
Derived key {HMAC-SHA-256} = 97B5A91D35AF542324881315C4F849E327C4707D1BC9D322
Derived key {HMAC-SHA-224} = 10CFFEDFB13503519969151E466F587028E0720B387F9AEF
Dim lpDK() As Byte
Dim strPassword As String
Dim lpSalt() As Byte
Dim nCount As Long
strPassword = "password"
lpSalt = cnvBytesFromHexStr("78 57 8E 5A 5D 63 CB 06")
nCount = 2048
lpDK = pbeKdf2(24, StrConv(strPassword, vbFromUnicode), lpSalt, nCount)
Debug.Print "Derived key = " & cnvHexStrFromBytes(lpDK)
Debug.Print "Correct key = BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"
lpDK = pbeKdf2(24, StrConv(strPassword, vbFromUnicode), lpSalt, nCount, PKI_HASH_SHA256)
Debug.Print "Derived key {HMAC-SHA-256} = " & cnvHexStrFromBytes(lpDK)
Debug.Print "Correct key {HMAC-SHA-256} = 97B5A91D35AF542324881315C4F849E327C4707D1BC9D322"
Derives a key of any length from a password using the PBKDF2 algorithm from PKCS #5 with the salt and output derived key encoded in hexadecimal.
Public Declare Function PBE_Kdf2Hex Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nMaxChars As Long, ByVal nKeyBytes As Long,
ByVal strPwd As String, ByVal strSaltHex As String,
ByVal nCount As Long, ByVal nOptions As Long) As Long
nRet = PBE_Kdf2Hex(strDerivedKey, nMaxChars, nKeyLen, strPassword, strSaltHex, nCount, nOptions)
long __stdcall PBE_Kdf2Hex(char *szOutput, long nMaxChars, long dkBytes, const char *szPwd, const char *szSaltHex, long nCount, long nOptions);
If successful, the return value is 0; otherwise it returns a non-zero error code.
Public Function pbeKdf2Hex (dkBytes As Long, szPwd As String, szSaltHex As String, nCount As Long, Optional nOptions As Long = 0) As String
Pbe.Kdf2 Method (Int32, String, String, Int32, HashAlgorithm)
The output string szOutput should be pre-dimensioned to be at least double the
required key length in bytes. (Hint: specify nMaxChars as Len(strOutput)).
ANSI C users must add one to this value when allocating memory.
The seed szSaltHex is specified in hex format and can be any even number of hex digits in length.
The password szPassword is normal text, not hexadecimal.
Dim strDerivedKey As String Dim nKeyLen As Long Dim strPassword As String Dim strSaltHex As String Dim nCount As Long Dim nRet As Long strPassword = "password" ' NB normal text, not hex ' Set 8-byte salt = 78 57 8E 5A 5D 63 CB 06 strSaltHex = "78578E5A5D63CB06" ' Iteration count is 2048 nCount = 2048 ' Pre-dimension output string for derived key to ' required length of 24 bytes i.e. 48 hex chars ' (Don't forget to do this) nKeyLen = 24 strDerivedKey = String(2 * nKeyLen, " ") ' Derive PBKDF2 key using function from CryptoSys API nRet = PBE_Kdf2Hex(strDerivedKey, Len(strDerivedKey), nKeyLen, _ strPassword, strSaltHex, nCount, 0) ' Check against test vector Debug.Print "Derived key = " & strDerivedKey Debug.Print "Correct key = BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"
This should result in output as follows:
Derived key = BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643 Correct key = BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643
Dim strDK As String
Dim strPassword As String
Dim strSaltHex As String
Dim nCount As Long
strPassword = "password"
strSaltHex = "78578E5A5D63CB06"
nCount = 2048
strDK = pbeKdf2Hex(24, strPassword, strSaltHex, nCount)
Debug.Print "Derived key = " & strDK
Debug.Print "Correct key = BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"
Derives a key of any length from a password using the SCRYPT algorithm.
Public Declare Function PBE_Scrypt Lib "diCrPKI.dll" (ByRef lpDerivedKey As Byte, ByVal nKeyLen As Long, ByRef lpPwd As Byte, ByVal nPwdLen As Long, ByRef lpSalt As Byte, ByVal nSaltLen As Long, ByVal nParamN As Long, ByVal nParamR As Long, ByVal nParamP As Long, ByVal nOptions As Long) As Long
nRet = PBE_Scrypt(abDerivedKey(0), nKeyLen, abPwd(0), nPwdLen, abSalt(0), nSaltLen, nParamN, nParamR, nParamP, nOptions)
' Note the "(0)" after the byte array parameters
long __stdcall PBE_Scrypt(unsigned char *lpDerivedKey, long nKeyLen, const unsigned char *lpPwd, long nPwdLen, const unsigned char *lpSalt, long nSaltLen, long nParamN, long nParamR, long nParamP, long nOptions);
"costParameter") a number greater than one and a power of 2."blockSize")"parallelizationParameter")If successful, the return value is 0; otherwise it returns a non-zero error code.
Public Function pbeScrypt (dkBytes As Long, lpPwd() As Byte, lpSalt() As Byte, nParamN As Long, nParamR As Long, nParamP As Long, Optional nOptions As Long = 0) As Byte()
Pbe.Scrypt Method (Int32, Byte[], Byte[], Int32, Int32, Int32)
static bvec_t dipki::Pbe::Scrypt (int dklen, const std::string password, const bvec_t &salt, int N, int r, int p)
static Pbe.scrypt(dklen, pwdbytes, salt, N, r, p)
This uses the SCRYPT algorithm from [RFC7914]. There are restrictions on the values of the parameters N, r and p. In particular, N must be larger than 1 and a power of 2. The output buffer for the derived key abDerivedKey must have been dimensioned to at least the required length nKeyLen in bytes.
Two examples from [RFC7914].
Dim abPwd() As Byte Dim abSalt() As Byte Dim abDK() As Byte Dim nKeyLen As Long Dim nPwdlen As Long Dim nSaltLen As Long Dim nRet As Long nKeyLen = 64 ' Dimension key byte array ReDim abDK(nKeyLen - 1) ' Convert strings to byte array form abPwd = StrConv("password", vbFromUnicode) abSalt = StrConv("NaCl", vbFromUnicode) ' Get lengths in bytes nPwdlen = UBound(abPwd) + 1 nSaltLen = UBound(abSalt) + 1 ' Call the SCRYPT function to derive a 64-byte key with parameters N=1024, r=8, p=16 nRet = PBE_Scrypt(abDK(0), nKeyLen, abPwd(0), nPwdlen, abSalt(0), nSaltLen, 1024, 8, 16, 0) Debug.Print "PBE_Scrypt() returns " & nRet & " (expecting 0)" Debug.Print "KEY=" & cnvHexStrFromBytes(abDK)
PBE_Scrypt() returns 0 (expecting 0) KEY=FDBABE1C9D3472007856E7190D01E9FE7C6AD7CBC8237830E77376634B373162 2EAF30D92E22A3886FF109279D9830DAC727AFB94A83EE6D8360CBDFA2CC0640
In this second example, we need to pass zero-length byte arrays (representing the empty string) for the password and salt.
' INPUT: (N=16, r=1, p=1) ' P="", S="" => empty strings => byte arrays of length zero ' VBA ISSUE: we cannot pass an empty byte array in the usual way `abPwd(0)` ' because it gives a "Subscript out of range" error. ' FIX: pass `0` for the array parameters and zero for the lengths nRet = PBE_Scrypt(abDK(0), nKeyLen, 0, 0, 0, 0, 16, 1, 1, 0) Debug.Print "PBE_Scrypt() returns " & nRet & " (expecting 0)" Debug.Print "KEY=" & cnvHexStrFromBytes(abDK)
PBE_Scrypt() returns 0 (expecting 0) KEY=77D6576238657B203B19CA42C18A0497F16B4844E3074AE8DFDFFA3FEDE21442 FCD0069DED0948F8326A753A0FC81F17E8D3E0FB2E0D3628CF35E20C38D18906
Dim lpPwd() As Byte
Dim lpSalt() As Byte
Dim lpDK() As Byte
lpPwd = StrConv("password", vbFromUnicode)
lpSalt = StrConv("NaCl", vbFromUnicode)
lpDK = pbeScrypt(64, lpPwd, lpSalt, 1024, 8, 16, 0)
Debug.Print "DK=" & cnvHexStrFromBytes(lpDK)
Debug.Print "OK=FDBABE1C9D3472007856E7190D01E9FE7C6AD7CBC8237830E77376634B3731622EAF30D92E22A3886FF109279D9830DAC727AFB94A83EE6D8360CBDFA2CC0640"
' INPUT: (N=16, r=1, p=1)
' P="", S="" => empty strings => byte arrays of length zero
' IMPORTANT: dummy variables *must* be independent
Dim lpDummy1() As Byte
Dim lpDummy2() As Byte
lpDK = pbeScrypt(64, lpDummy1, lpDummy2, 16, 1, 1, 0)
Debug.Print "DK=" & cnvHexStrFromBytes(lpDK)
Debug.Print "OK=77D6576238657B203B19CA42C18A0497F16B4844E3074AE8DFDFFA3FEDE21442FCD0069DED0948F8326A753A0FC81F17E8D3E0FB2E0D3628CF35E20C38D18906"
Dim strDerivedKey As String
strDerivedKey = pbeScryptHex(64, "pleaseletmein", cnvHexStrFromString("SodiumChloride"), 16384, 8, 1, 0)
Debug.Print "Derived key = " & strDerivedKey
Debug.Print "OK = " & "7023BDCB3AFD7348461C06CD81FD38EBFDA8FBBA904F8E3EA9B543F6545DA1F2D5432955613F0FCF62D49705242A9AF9E61E85DC0D651E40DFCF017B45575887"
Derives a key of any length from a password using the SCRYPT algorithm with the salt and derived key encoded in hexadecimal.
Public Declare Function PBE_ScryptHex Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nMaxChars As Long, ByVal dkBytes As Long, ByVal strPwd As String, ByVal strSaltHex As String, ByVal nParamN As Long, ByVal nParamR As Long, ByVal nParamP As Long, ByVal nOptions As Long) As Long
nRet = PBE_ScryptHex(strDerivedKey, nMaxChars, dkBytes, strPassword, strSaltHex, nParamN, nParamR, nParamP, nOptions)
long __stdcall PBE_ScryptHex(char *szOutput, long nMaxChars, long dkBytes, const char *szPwd, const char *szSaltHex, long nParamN, long nParamR, long nParamP, long nOptions);
"costParameter") a number greater than one and a power of 2."blockSize")"parallelizationParameter")If successful, the return value is 0; otherwise it returns a non-zero error code.
Public Function pbeScryptHex (dkBytes As Long, szPwd As String, szSaltHex As String, nParamN As Long, nParamR As Long, nParamP As Long, Optional nOptions As Long = 0) As String
Pbe.Scrypt Method (Int32, String, String, Int32, Int32, Int32)
The output string szOutput should be pre-dimensioned to be at least double the
required key length in bytes. (Hint: specify nMaxChars as Len(strOutput)).
The seed szSaltHex is specified in hex format and can be any even number of hex digits in length.
The password szPassword is normal text, not hexadecimal.
Dim strDerivedKey As String Dim nKeyLen As Long Dim strPassword As String Dim strSaltHex As String Dim nRet As Long strPassword = "pleaseletmein" ' NB normal text, not hex strSaltHex = cnvHexStrFromString("SodiumChloride") ' Pre-dimension output string for derived key to ' required length of two times number of bytes ' (Don't forget to do this) nKeyLen = 64 strDerivedKey = String(2 * nKeyLen, " ") ' Derive key using SCRYPT nRet = PBE_ScryptHex(strDerivedKey, Len(strDerivedKey), nKeyLen, _ strPassword, strSaltHex, 16384, 8, 1, 0) Debug.Print "Derived key = " & strDerivedKey
This should result in output as follows:
Derived key = 7023BDCB3AFD7348461C06CD81FD38EBFDA8FBBA904F8E3EA9B543F6545DA1F2 D5432955613F0FCF62D49705242A9AF9E61E85DC0D651E40DFCF017B45575887
Dim strDerivedKey As String
strDerivedKey = pbeScryptHex(64, "pleaseletmein", cnvHexStrFromString("SodiumChloride"), 16384, 8, 1, 0)
Debug.Print "Derived key = " & strDerivedKey
Debug.Print "OK = " & "7023BDCB3AFD7348461C06CD81FD38EBFDA8FBBA904F8E3EA9B543F6545DA1F2D5432955613F0FCF62D49705242A9AF9E61E85DC0D651E40DFCF017B45575887"
Creates a PEM file from a binary file .
Public Declare Function PEM_FileFromBinFile Lib "diCrPKI.dll"
(ByVal strOutputFile As String, ByVal strFileIn As String,
ByVal strHeader As String, ByVal nLineLen As Long) As Long
nRet = PEM_FileFromBinFile(strOutputFile, strFileIn, strHeader, nLineLen)
long __stdcall PEM_FileFromBinFile(const char *szFileOut, const char *szFileIn, const char *szHeader, long nLineLen);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Pem.FileFromBinFile Method Pem.FileFromBinFile Method
static int dipki::Pem::FileFromBinFile (const std::string &fileToMake, const std::string &fileIn, const std::string &header="", int lineLen=0, Eol eol=Eol::Windows)
This function takes the contents of any file (usually an ASN.1 DER- or BER-encoded binary file), treats it as binary data, encodes in base64 format, and encapsulates in a PEM-style header and footer. Leave the header blank to omit the PEM encapsulation and just output plain base64. The default for nLineLen is 64 characters. The recommended limit is 72 characters.
A PEM file is a text file containing encapsulated base64 data of the form
-----BEGIN FOO BAR----- MIAGCSqGSIb3DQEHA... -----END FOO BAR-----
The label in the header between "BEGIN " and the following five dash characters "-----" is set
using the szHeader parameter.
In the above example, strHeader="FOO BAR". You are free to use whatever word or words you like.
In this Toolkit, we make no checks that the content of the file matches the header. However, other applications may.
Here is a list of commonly-used headers for PKI-related files.
| PEM Header | Type of file | Typical file extensions | Comment |
|---|---|---|---|
CERTIFICATE | X.509 certificate | .cer,.der,.pem,.crt | Should contain exactly one certificate |
CERTIFICATE REQUEST | PKCS#10 certificate signing request | .csr,.p10 | |
X509 CRL | X.509 certificate revocation list | .crl | |
PKCS12 | PFX file to PKCS#12 | .p12,.pfx | |
ENCRYPTED PRIVATE KEY | PKCS#8 key | .p8e,.key,(.epk) | Our default private key format |
RSA PUBLIC KEY | PKCS#1 public key | .p1,.pub | Our default public key format |
PUBLIC KEY | SubjectPublicKeyInfo | | OpenSSL format (PKI_KEY_FORMAT_SSL) |
PRIVATE KEY | Unencrypted PKCS#8 private key info | .p8,.pri,.key | Our private key info format |
RSA PRIVATE KEY | Unencrypted PKCS#1 private key | | OpenSSL format (PKI_KEY_FORMAT_SSL) |
PKCS7 | CMS object to PKCS#7 | .p7m,.p7s,.p7c,.p7b,.p7z | Used by OpenSSL |
PKCS #7 SIGNED DATA | ditto | | Used by Thawte for Microsoft users |
NETSCAPE CERTIFICATE CHAIN | "certs-only" PKCS#7 | .p7c,.p7b | Used by Thawte for Netscape users |
Update April 2015: see RFC 7468 "Textual Encodings of PKIX, PKCS, and CMS Structures" [RFC7468] for more definitive rules and recommendations on this subject.
Dim nRet As Long Dim strBinFile As String Dim strPemFile As String Dim strDigest As String ' Input file is a DER-encoded X.509 certificate ' (at 227 bytes, the smallest we could devise) strBinFile = "smallca.cer" strPemFile = "smallca.pem.cer" ' Convert to a PEM file nRet = PEM_FileFromBinFile(strPemFile, strBinFile, "CERTIFICATE", 72) Debug.Print "PEM_FileFromBinFile returns " & nRet & " (expecting 0)" ' To prove we did it properly, compute the thumbprint of the two certs strDigest = String(PKI_SHA1_CHARS, " ") nRet = X509_CertThumb(strBinFile, strDigest, Len(strDigest), PKI_HASH_SHA1) If nRet > 0 Then Debug.Print "SHA-1(der-file)=" & strDigest Else Debug.Print "ERROR: computing cert thumb" End If nRet = X509_CertThumb(strPemFile, strDigest, Len(strDigest), PKI_HASH_SHA1) If nRet > 0 Then Debug.Print "SHA-1(pem-file)=" & strDigest Else Debug.Print "ERROR: computing cert thumb" End If
The output should be
PEM_FileFromBinFile returns 0 (expecting 0) SHA-1(der-file)=a36b1bfa0af41a2785066b2d5135b67011ac3b7f SHA-1(pem-file)=a36b1bfa0af41a2785066b2d5135b67011ac3b7f
The X.509 file in this example is
-----BEGIN CERTIFICATE----- MIHgMIGaAgEBMA0GCSqGSIb3DQEBBQUAMAwxCjAIBgNVBAMTAUEwHhcNMDcwODAyMDIwMDAx WhcNMTEwODAyMDIwMDAxWjAMMQowCAYDVQQDEwFBMEowDQYJKoZIhvcNAQEBBQADOQAwNgIx A1KSJlPSmQAqQgDHUISaUsCrHbIZe249i6jFtfN3rA7czrP4CXS3mjvMFf0AsxV6BwIBAzAN BgkqhkiG9w0BAQUFAAMyAACeT7GtgmBRKUN20cIyNEGneEvmNxaliuBEVkg2npbyEBgeHXOH 6jqj9Ase348UN/Q= -----END CERTIFICATE-----
The binary file is
000000 30 81 e0 30 81 9a 02 01 01 30 0d 06 09 2a 86 48 0..0.....0...*.H
000010 86 f7 0d 01 01 05 05 00 30 0c 31 0a 30 08 06 03 ........0.1.0...
000020 55 04 03 13 01 41 30 1e 17 0d 30 37 30 38 30 32 U....A0...070802
000030 30 32 30 30 30 31 5a 17 0d 31 31 30 38 30 32 30 020001Z..1108020
000040 32 30 30 30 31 5a 30 0c 31 0a 30 08 06 03 55 04 20001Z0.1.0...U.
000050 03 13 01 41 30 4a 30 0d 06 09 2a 86 48 86 f7 0d ...A0J0...*.H...
000060 01 01 01 05 00 03 39 00 30 36 02 31 03 52 92 26 ......9.06.1.R.&
000070 53 d2 99 00 2a 42 00 c7 50 84 9a 52 c0 ab 1d b2 S...*B..P..R....
000080 19 7b 6e 3d 8b a8 c5 b5 f3 77 ac 0e dc ce b3 f8 .{n=.....w......
000090 09 74 b7 9a 3b cc 15 fd 00 b3 15 7a 07 02 01 03 .t..;......z....
0000a0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 03 0...*.H.........
0000b0 32 00 00 9e 4f b1 ad 82 60 51 29 43 76 d1 c2 32 2...O...`Q)Cv..2
0000c0 34 41 a7 78 4b e6 37 16 a5 8a e0 44 56 48 36 9e 4A.xK.7....DVH6.
0000d0 96 f2 10 18 1e 1d 73 87 ea 3a a3 f4 0b 1e df 8f ......s..:......
0000e0 14 37 f4 .7.
>certmgr smallca.cer
==============Certificate # 1 ==========
Subject::
[0,0] 2.5.4.3 (CN) A
Issuer::
[0,0] 2.5.4.3 (CN) A
SerialNumber::
01
SHA1 Thumbprint::
A36B1BFA 0AF41A27 85066B2D 5135B670 11AC3B7F
MD5 Thumbprint::
575A5AEE 32B3810F EFA71CEC 5EAD35DD
Key MD5 Thumbprint::
42B4A712 FB3B4C12 B75CB679 1D0C0E01
NotBefore::
Thu Aug 02 10:00:01 2007
NotAfter::
Tue Aug 02 10:00:01 2011
==============No CTLs ==========
==============No CRLs ==========
==============================================
CertMgr Succeeded
PEM_FileFromBinFileEx PEM_FileToBinFile
Creates a PEM file from a binary file with extended options.
Public Declare Function PEM_FileFromBinFileEx Lib "diCrPKI.dll"
(ByVal strOutputFile As String, ByVal strFileIn As String, ByVal strHeader As String, ByVal nLineLen As Long, ByVal nOptions As Long) As Long
nRet = PEM_FileFromBinFileEx(strOutputFile, strFileIn, strHeader, nLineLen, nOptions)
long __stdcall PEM_FileFromBinFileEx(const char *szFileOut, const char *szFileIn, const char *szHeader, long nLineLen, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Pem.FileFromBinFile Method Pem.FileFromBinFile Method
static Pem.from_binfile(outputfile, filein, header, linelen=64, eol=EOL.DEFAULT)
See the remarks for PEM_FileFromBinFile(). This extension was added to create PEM format files compatible with those created by Open SSL, which uses Unix line endings (a single LF character as opposed to the CR-LF pair used in Windows files).
PEM_FileFromBinFile PEM_FileToBinFile
Converts the contents of a PEM file into a binary file.
Public Declare Function PEM_FileToBinFile Lib "diCrPKI.dll"
(ByVal strOutputFile As String, ByVal strFileIn As String) As Long
nRet = PEM_FileToBinFile(strOutputFile, strFileIn)
long __stdcall PEM_FileToBinFile(const char *szFileOut, const char *szFileIn);
If successful, the return value is zero; otherwise it returns a nonzero error code.
static int dipki::Pem::FileToBinFile (const std::string &fileToMake, const std::string &fileIn)
static Pem.to_binfile(outputfile, filein)
Any base64-encoded data found between a PEM header and footer is converted into binary data and saved as a file.
-----BEGIN FOO BAR----- MIAGCSqGSIb3DQEHA... -----END FOO BAR-----
Dim nRet As Long Dim strBinFile As String Dim strPemFile As String Dim strDigest As String ' Input file is a PEM-encoded X.509 certificate strPemFile = "smallca.pem.cer" strBinFile = "smallca-copy.cer" ' Convert to a binary file nRet = PEM_FileToBinFile(strBinFile, strPemFile) Debug.Print "PEM_FiletoBinFile returns " & nRet & " (expecting 0)"
Creates a simple PFX (PKCS-12) file from an X.509 certificate and (optional) encrypted private key file.
Public Declare Function PFX_MakeFile Lib "diCrPKI.dll"
(ByVal strOutputFile As String, ByVal strCertList As String,
ByVal strKeyFile As String, ByVal strPassword As String,
ByVal strFriendlyName As String, ByVal nOptions As Long) As Long
nRet = PFX_MakeFile(strOutputFile, strCertList, strKeyFile, strPassword, strFriendlyName, nOptions)
long __stdcall PFX_MakeFile(const char *szFileOut, const char *szCertList, const char *szEpkFile, const char *szPassword, const char *szFriendlyName, long nOptions);
;)."" to exclude the private key.
If successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function pfxMakeFile (szFileOut As String, szCertList As String, Optional szKeyFile As String = "", Optional szPassword As String = "", Optional szFriendlyName As String = "", Optional nOptions As Long = 0) As Long
static int dipki::Pfx::MakeFile (const std::string &fileToMake, const std::string &certList, const std::string &privateKeyFile="", const std::string &password="", const std::string &friendlyName="", Opts opts=Opts::Default)
static Pfx.make_file(outputfile, certlist, prikeyfile="", password="", friendlyname="", opts=0)
At least one certificate must be specified in the szCertList argument. Add additional certificate names (or base64 representations)
separated by a semicolon (;).
The first certificate in the list must be the matching certificate for the private key, if included.
The default behaviour is to save the certificate(s) encrypted using the "standard" weak 40-bit
RC2 encryption (pbeWithSHAAnd40BitRC2-CBC) as used (until recently) by Windows Certificate Manager and OpenSSL,
and the private key is re-encrypted using the "standard" TripleDES-SHA1 algorithm (pbeWithSHAAnd3-KeyTripleDES-CBC).
[New in v12.3] Use the PKI_PFX_STRONG_CERT option to encrypt the certificate with "stronger" Triple DES, the same as the default key encryption algorithm. The PKI_PFX_PLAIN_CERT option takes precedence.
[New in v20.5] Use the PKI_PFX_AES256_SHA256 option to encrypt both the private key and certificate using "AES256-SHA256".
The szFriendlyName parameter is optional. To exclude the private key just pass an empty szKeyFile parameter.
To help users of a certain brain-dead web service in Mexico which cannot cope with anything else,
the default file format is the exact format that would be created by OpenSSL.
If you really need Microsoft's peculiarities†, then
add the PKI_PFX_ALT_FORMAT option flag.
Any form of PKCS-12 file created by this function should be importable into
Windows Certificate Manager/Outlook (use a .pfx extension for the output file) and Mozilla/Firefox (use a .p12 extension).
The PKCS-12 standard is notorious for its peculiarities - see
PFX - How Not to Design a Crypto Protocol/Standard
[GUTPFX].
If you do not have success with your target application, try changing the options.
In particular, using the PKI_PFX_CLONE_KEY option may cause problems if the target application cannot
decrypt the super-secure algorithm you've used to protect your private key
(error messages about a missing cryptographic provider are a clue here).
That's why the default behaviour is to re-encrypt using the "standard" algorithm.
If you specify both a certificate and a private key,
their RSA keys must match or a PKI_NO_MATCH_ERROR error will occur.
The PKCS-12 file will be protected using the specified szPassword, which must match the password
for the encrypted private key file, if included.
The password is optional for the case where there is just a certificate, but is required
if you need the certificate to be encrypted.
If you don't use a password for a cert-only file, just enter an empty password
when importing the PFX into Windows.
If you use the PKI_KEY_FORMAT_PEM option, the output file will be in PEM format with the
first line "-----BEGIN PKCS12-----".
Be warned, Windows does not recognise such a file as a valid PFX/PKCS-12 format!
† The difference between the OpenSSL and Microsoft forms is that the Microsoft form has a "preferredAbsent" NULL parameter added to the message digest object for "sha1" and uses 8 instead of 20 bytes for the MacData salt. Both combinations are perfectly valid according to the PKCS12 specification.
This example uses Bob's X.509 certificate and encrypted private key file to create a pkcs-12 file and then verifies the signature. The resulting file should be importable into Windows Certficate Manager or Mozilla with an exportable private key.
Dim strOutputFile As String Dim strCertFile As String Dim strKeyFile As String Dim strPassword As String Dim nRet As Long strOutputFile = "Bob1.pfx" strCertFile = "BobRSASignByCarl.cer" strKeyFile = "BobPrivRSAEncrypt.p8e" strPassword = "password" ' Given Bob's certificate and encrypted private key file (with password "password"), ' create a PKCS-12 (pfx/p12) file. nRet = PFX_MakeFile(strOutputFile, strCertFile, strKeyFile, strPassword, "Bob's ID", 0) Debug.Print "PFX_MakeFile returns " & nRet ' Now verify that the signature is OK nRet = PFX_VerifySig(strOutputFile, strPassword, 0) Debug.Print "PFX_VerifySig returns " & nRet ' Clean up Call WIPE_String(strPassword, Len(strPassword))
Both functions should return zero.
The next example uses Carl's X.509 certificate to create a "certificate-only" pkcs-12 file. This is useful for importing the certificate into Mozilla/Firefox. Enter a blank password when importing.
Dim strOutputFile As String Dim strCertFile As String Dim strKeyFile As String Dim nRet As Long strOutputFile = "CarlNoKey.p12" strCertFile = "CarlRSASelf.cer" ' Given Carl's certificate only, ' create a PKCS-12 (pfx/p12) file with no private key. nRet = PFX_MakeFile(strOutputFile, strCertFile, "", "", "Carl's ID", 0) Debug.Print "PFX_MakeFile returns " & nRet
The next example in C/C++ creates a pkcs-12 file in PEM format, using key and certificate data passed as strings.
long nRet; char *outfile = "bob-pemfull.p12"; char *pfile; char *password = "password"; char *epkstr = /* From BobPrivRSAEncrypt.p8e */ "-----BEGIN ENCRYPTED PRIVATE KEY-----""\n" "MIICojAcBgoqhkiG9w0BDAEDMA4ECFolTdEnFcG+AgIH0ASCAoBUZJEzzH//" "TRl5ieAHPo9q1eoMlYQu6j/eF8iIMNQ/eUp41iQIXqt9gcO2YdU5ah+ooMu4" "ef1+yMN0buWUKFLgyUTyoYdg3O8XrCB6GhCCPeTXYvt6vYs4w85HHaXMZdfz" "6dXAq3ratOVGq0PYg9dF0nI5T6Yd8S29TX4ceWyhNVG9yXAQhsRO1mMlS1tw" "aTtxME7OSsQXe4mFgqGiCTwmNA183VqXdXP+1D2IrpI2zN+JfmTvOQIQ0iU8" "ZuqBDMDRm8M/60uh2RlrfLqaIXKlF1V9PddijM6ORu8FFyPfaXkwZ7VsuvRS" "Iijpf9PNDh4J+E0Vy1lsc6r4RrZWHdc4kKwKpYalE45wME14sbvh+WCZmFfd" "D/pLZM8Or/IVHGYPFbpoAZwy+bmsjjOH/dBg6q1CY8mme9dnCBVLfXoZXTTk" "o9TOSFw4Tmd/YEH2yPylT78hw+ThNsNmG2PwUX+5yTFoI7PQA8oBg6sN4kbP" "tuRSo1fcB9RqJEO5hhqo+xAoMdhlHWdbIXOcEa1S8zLisJmgVrdAHJz6PPBl" "3LVe1LHZ/oOD8rxeal8GTTCLk4onhjr7IT+DipMJendcjIgyok5I14DiKmjt" "UPL10bt+0XkRVCIM0jma80YIGs4OMgRdW4u4n4lzJ0c1pxbvQvz8LY65OLcI" "M+6VqJCH360iN1CSLRbVBg6HqjMNEthEXExKh/b95u+sVd4qPINmsnD1DwTd" "4vkWx1zM4T+sKdz2GnBrjNRu2nJ4Nqe/krxDEKvcowh0eNllS/J86LhLYFFg" "z/JKcqq20+GPSaQALvVXK7mVKljZcKEI6YQKQMgt5+amnDixhbvppSn/my1o" "0kG3" "-----END ENCRYPTED PRIVATE KEY-----"; char *certstr = /* From BobRSASignByCarl.cer */ "-----BEGIN CERTIFICATE-----""\n" "MIICJzCCAZCgAwIBAgIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQUFADAS" "MRAwDgYDVQQDEwdDYXJsUlNBMB4XDTk5MDkxOTAxMDkwMloXDTM5MTIzMTIzNTk1" "OVowETEPMA0GA1UEAxMGQm9iUlNBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB" "gQCp4WeYPznVX/Kgk0FepnmJhcg1XZqRW/sdAdoZcCYXD72lItA1hW16mGYUQVzP" "t7cIOwnJkbgZaTdt+WUee9mpMySjfzu7r0YBhjY0MssHA1lS/IWLMQS4zBgIFEjm" "Txz7XWDE4FwfU9N/U9hpAfEF+Hpw0b6Dxl84zxwsqmqn6wIDAQABo38wfTAMBgNV" "HRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIFIDAfBgNVHSMEGDAWgBTp4JAnrHggeprT" "TPJCN04irp44uzAdBgNVHQ4EFgQU6PS4Z9izlqQq8xGqKdOVWoYWtCQwHQYDVR0R" "BBYwFIESQm9iUlNBQGV4YW1wbGUuY29tMA0GCSqGSIb3DQEBBQUAA4GBAHuOZsXx" "ED8QIEyIcat7QGshM/pKld6dDltrlCEFwPLhfirNnJOIh/uLt359QWHh5NZt+eIE" "VWFFvGQnRMChvVl52R1kPCHWRbBdaDOS6qzxV+WBfZjmNZGjOd539OgcOyncf1EH" "l/M28FAK3Zvetl44ESv7V+qJba3JiNiPzyvT" "-----END CERTIFICATE-----"; nRet = PFX_MakeFile(outfile, certstr, epkstr, password, "Bob's friendly ID", PKI_KEY_FORMAT_PEM); if (nRet != 0) disp_error(nRet); assert(nRet == 0); printf("Created file '%s'\n", outfile); pfile = outfile; nRet = PFX_VerifySig(pfile, password, 0); if (nRet != 0) disp_error(nRet); assert(nRet == 0); printf("Verified file '%s'\n", pfile);
PFX_VerifySig RSA_GetPrivateKeyFromPFX RSA_ReadPrivateKeyFromPFX
Verifies the signature in a pkcs-12 file.
Public Declare Function PFX_VerifySig Lib "diCrPKI.dll"
(ByVal strPfxFile As String, ByVal strPassword As String,
ByVal nOptions As Long) As Long
nRet = PFX_VerifySig(strPfxFile, strPassword, nOptions)
long __stdcall PFX_VerifySig(const char *szFileName, const char *szPassword, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
static Pfx.sig_is_valid(pfxfile, password)
Just checks that the MacData signature is OK using the given password. Makes no other checks. The PFX file can be in either BER-encoded binary or PEM format. You can also pass the data directly as a PEM string in the szPfxFile parameter.
[New in v3.8] If there is no MacData signature in the PFX file and the supplied szPassword is empty, it will consider that to be a "valid" signature and return zero.
See the example for PFX_MakeFile above.
PFX_MakeFile RSA_GetPrivateKeyFromPFX
Retrieves the date and time the toolkit executable was last compiled.
Public Declare Function PKI_CompileTime Lib "diCrPKI.dll"
(ByVal strCompiledOn As String, ByVal nStrLen As Long) As Long
nRet = PKI_CompileTime(strCompiledOn, nStrLen)
long __stdcall PKI_CompileTime(char *szOutput, long nOutChars);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function pkiCompileTime() As String
static std::string dipki::Gen::CompileTime ()
static Gen.compile_time()
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
Dim nLen As Long
Dim strCompiledOn As String
strCompiledOn = String(255, " ")
nLen = PKI_CompileTime(strCompiledOn, Len(strCompiledOn))
strCompiledOn = Left(strCompiledOn, nLen)
Debug.Print "PKI_CompileTime returns " & nLen & " [" & strCompiledOn & "]"
Debug.Print pkiCompileTime()
Debug.Print pkiModuleInfo()
Debug.Print pkiModuleName()
Debug.Print pkiPlatform()
Returns the error code of the first error that occurred when calling the last function.
Public Declare Function PKI_ErrorCode Lib "diCrPKI.dll" () As Long
nRet = PKI_ErrorCode()
long __stdcall PKI_ErrorCode(void);
None.
Returns the error code for the first error that occurred when calling the last function, or zero if no error occurred. This may be different from the error code returned by the function itself if more than one error occurred during the call to the function.
Public Function pkiErrorCode() As Long
static Gen.error_code()
The value returned is always a non-negative integer.
For example, a call to CMS_MakeEnvData with one invalid X.509 certificate out of
three would return 2 indicating two successful recipients.
A call to PKI_ErrorCode() will
indicate the error code for the invalid certificate.
PKI_LastError() should have a more detailed error message.
Dim nErrCode as Long
nErrCode = PKI_ErrorCode()
PKI_LastError PKI_ErrorLookup Error codes
Retrieves the error message associated with a given error code.
Public Declare Function PKI_ErrorLookup Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nOutChars As Long, ByVal nErrCode As Long) As Long
nRet = PKI_ErrorLookup(strOutput, nOutChars, nErrCode)
long __stdcall PKI_ErrorLookup(char *szOutput, long nOutChars, long nErrCode);
The number of characters that have been set in szOutput. If the function is called with nOutChars set to zero or szOutput as NULL, the return value is the number of characters in the error message.
Public Function pkiErrorLookup (nErrCode As Long) As String
static std::string dipki::Err::ErrorLookup (int errCode)
static Gen.error_lookup(n)
Specify a zero nOutChars or an empty string for szOutput to find the required length of the output string. ANSI C users must add one to this value when allocating memory.
The error message will never be longer than 127 characters (PKI_MAX_ERRORLOOKUP_CHARS).
Dim nLen As Long
Dim nErrCode As Long
Dim strErrMsg As String * 128
nErrCode = 25
nLen = PKI_ErrorLookup(strErrMsg, Len(strErrMsg), nErrCode)
Debug.Print "ErrorLookup(" & nErrCode & ")=" & Left(strErrMsg, nLen)
This should return
ErrorLookup(25)=Certificate issuer error
Dim nErrCode As Long
For nErrCode = 1 To 11
Debug.Print nErrCode & " = " & pkiErrorLookup(nErrCode)
Next
Return a formatted error message string for the last error.
No direct call from VBA/VB6. Use errFormatErrorMessage
long __stdcall PKI_FormatErrorMessage(char *szOutput, long nOutChars, long nErrCode, const char *szUserMsg);
The number of characters that have been set in szOutput.
General.FormatErrorMessage Method
static std::string dipki::Err::FormatErrorMessage (int errCode=0, const std::string &userMsg="")
This is a combination of PKI_ErrorLookup, PKI_ErrorCode and PKI_LastError to give a complete formatted error message, for example
ERROR (11): Value out of range (OUT_OF_RANGE_ERROR) ERROR: User message! (11): Value out of range (OUT_OF_RANGE_ERROR) ERROR (21): No match found (NO_MATCH_ERROR): (1) Cannot open input file (OPEN_ERROR): Private key does not match any certificate in list
The equivalent functions in other languages are written independently and will give similar but not identical outputs.
The error message will never be longer than 1023 characters plus the length of any user message. In the raw ANSI C function you can query the expected length, but it is recommended to write directly to a fixed size buffer, as in the example below.
char szErrMsg[1024]; long errcode = 11; PKI_FormatErrorMessage(szErrMsg, sizeof(szErrMsg) - 1, errcode, "User message!"); printf("%s\n", szErrMsg);
ERROR: User message! (11): Value out of range (OUT_OF_RANGE_ERROR)
PKI_ErrorLookup PKI_ErrorCode PKI_LastError Error codes
Retrieves the last error message set by the toolkit.
Public Declare Function PKI_LastError Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long) As Long
nRet = PKI_LastError(strOutput, nOutChars)
long __stdcall PKI_LastError(char *szOutput, long nOutChars);
If the preceding function call before calling PKI_LastError
was successful, the return value is
zero indicating no error; otherwise it is the number of characters that have been set in szOutput.
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length.
Specify a zero nOutChars or an empty string for szOutput to find the required length.
ANSI C users must add one to this value when allocating memory.
Public Function pkiLastError() As String
static std::string dipki::Err::LastError ()
static Gen.last_error()
Not all functions set the error message string. The error message will never be longer than 511 characters.
Sample C function to obtain the last error message.
/** Display error codes and corresponding messages. @param nRet Error code returned by last function. */ static void disp_error(long nRet) { long errcode; char lasterrmsg[PKI_MAX_LASTERROR_CHARS + 1] = { 0 }; char errlookupmsg[PKI_MAX_ERRORLOOKUP_CHARS + 1] = { 0 }; // Get error message that occurred when calling last function (if any) PKI_LastError(lasterrmsg, sizeof(lasterrmsg) - 1); // Get error code for first error that occurred (may be different from nRet) errcode = PKI_ErrorCode(); // Lookup message for error code if (errcode != 0) PKI_ErrorLookup(errlookupmsg, sizeof(errlookupmsg), errcode); else PKI_ErrorLookup(errlookupmsg, sizeof(errlookupmsg), nRet); // Display error details printf("ERROR Returned=%ld/Code=%ld: %s", nRet, errcode, errlookupmsg); // If we had a last error message, show it if (lasterrmsg[0]) printf(": %s\n", lasterrmsg); else printf("\n"); }
Dim s As String ' Valid function call, no error s = hashHexFromHex("616263", PKI_HASH_SHA1) Debug.Print "SHA1('abc')=" & s ' No error, so expecting empty string Debug.Print "LastError='" & pkiLastError() & "'" ' Force an error s = rsaFromXMLString("BADSTRING") Debug.Print "rsaFromXMLString(ERROR) returns '" & s & "'" Debug.Print "LastError='" & pkiLastError() & "'"
SHA1('abc')=a9993e364706816aba3e25717850c26c9cd0d89d
LastError=''
rsaFromXMLString(ERROR) returns ''
LastError='Cannot find valid RSAKeyValue or RSAKeyPair element'
PKI_ErrorCode PKI_ErrorLookup Error codes
Returns the ASCII value of the licence type.
Public Declare Function PKI_LicenceType Lib "diCrPKI.dll"
(ByVal nReserved As Long) As Long
nRet = PKI_LicenceType(nReserved)
long __stdcall PKI_LicenceType(long nOptions);
Returns the ASCII value of the licence type, either "D" (68, 0x44) for the Developer Version or "T" (84, 0x54) for the Trial Version.
Public Function pkiLicenceType (Optional nOptions As Long = 0) As String
static std::string dipki::Gen::LicenceType ()
static Gen.licence_type()
Note the Australian/English spelling of `Licence'.
Dim nRet As Long
nRet = PKI_LicenceType(0)
Debug.Print "PKI_LicenceType is " & Chr(nRet)
PKI_LicenceType is D
Get additional information about the core DLL module.
Public Declare Function PKI_ModuleInfo Lib "diCrPKI.dll"
(ByVal strName As String, ByVal nStrLen As Long, ByVal nOptions As Long) As Long
nRet = PKI_ModuleInfo(strName, nStrLen, 0)
long __stdcall PKI_ModuleInfo(char *szOutput, long nOutChars, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function pkiModuleInfo (Optional nOptions As Long = 0) As String
Dim nLen As Long Dim strModuleInfo As String nLen = PKI_ModuleInfo("", 0, 0) If nLen > 0 Then strModuleInfo = String(nLen, " ") nLen = PKI_ModuleInfo(strModuleInfo, nLen, 0) strModuleInfo = Left(strModuleInfo, nLen) Debug.Print "PKI_ModuleInfo returns " & nLen & " [" & strModuleInfo & "]" Else Debug.Print "Error " & nLen & " with PKI_ModuleInfo" End If
PKI_ModuleInfo returns 26 [Licensed Developer Edition]
Debug.Print pkiCompileTime()
Debug.Print pkiModuleInfo()
Debug.Print pkiModuleName()
Debug.Print pkiPlatform()
Retrieves the name of the current process's module.
Public Declare Function PKI_ModuleName Lib "diCrPKI.dll"
(ByVal strName As String, ByVal nStrLen As Long, ByVal nOptions As Long) As Long
nRet = PKI_ModuleName(strName, nStrLen, 0)
long __stdcall PKI_ModuleName(char *szOutput, long nOutChars, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function pkiModuleName (Optional nOptions As Long = 0) As String
static std::string dipki::Gen::ModuleName ()
static Gen.module_name()
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
If using the Win32 DLL in the system folder on a 64-bit system,
Windows will return "C:\WINDOWS\SYSTEM32\diCrPKI.dll" when the DLL file path is actually
"C:\WINDOWS\SYSWOW64\diCrPKI.dll".
Use PKI_Platform to find out exactly which DLL is being used.
Dim nLen As Long Dim strModuleName As String nLen = PKI_ModuleName("", 0, 0) If nLen > 0 Then strModuleName = String(nLen, " ") nLen = PKI_ModuleName(strModuleName, nLen, 0) strModuleName = Left(strModuleName, nLen) Debug.Print "PKI_ModuleName returns " & nLen & " [" & strModuleName & "]" Else Debug.Print "Error " & nLen & " with PKI_ModuleName" End If
On our W10 system, this produces the output:
PKI_ModuleName returns 31 [C:\WINDOWS\SYSTEM32\diCrPKI.dll]
Debug.Print pkiCompileTime()
Debug.Print pkiModuleInfo()
Debug.Print pkiModuleName()
Debug.Print pkiPlatform()
Gets the platform the core DLL was compiled for.
Public Declare Function PKI_Platform Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nOutChars As Long) As Long
nRet = PKI_Platform(strOutput, nOutChars)
long __stdcall PKI_Platform(char *szOutput, long nOutChars);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function pkiPlatform() As String
static std::string dipki::Gen::Platform ()
static Gen.core_platform()
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
Debug.Print pkiCompileTime()
Debug.Print pkiModuleInfo()
Debug.Print pkiModuleName()
Debug.Print pkiPlatform()
Carries out on demand the full set of power-up tests automatically performed by the toolkit when first powered up (i.e. when the DLL is first attached to the process).
Public Declare Function PKI_PowerUpTests Lib "diCrPKI.dll"
(ByVal nOptions As Long) As Long
nRet = PKI_PowerUpTests(nOptions)
long __stdcall PKI_PowerUpTests(long nOptions);
If successful, returns zero; otherwise it returns a nonzero error code.
This is an optional function. Unlike the tests carried out on actual power-up, this function does not cause the DLL to quit. If errors do occur, an error event will be recorded in the Application event log for NT+ operating systems or in an error log file on W9x systems. For more information on error logging after a self-test error, see Self Tests. Users are warned not to use the toolkit if an error has occurred after using this optional test. In such an event, please contact us.
Dim nRet As Long
nRet = PKI_PowerUpTests(0)
Debug.Print "PKI_PowerUpTests returns " & nRet
Retrieves the release version number.
Public Declare Function PKI_Version Lib "diCrPKI.dll"
(ByVal nReserved1 As Long, ByVal nReserved2 As Long) As Long
nRet = PKI_Version(0, 0)
long __stdcall PKI_Version(void *nReserved1, void *nReserved2);
Version number as an integer in form
Major*100*100 + Minor*100 + Revision.
For example, version 20.1.2 would return 200102.
If this function fails, it means the toolkit is not installed or the library cannot be found.
Public Function pkiVersion() As Long
static int dipki::Gen::Version ()
static Gen.version()
The arguments nReserved1 and nReserved2 are ignored.
Dim nRet As Long nRet = PKI_Version(0, 0) Debug.Print "PKI_Version returns " & nRet ' PKI_Version returns 200301
PKI_LicenceType PKI_CompileTime
Generate output bytes using a pseudorandom function (PRF).
Public Declare Function PRF_Bytes Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpMessage As Byte, ByVal nMsgLen As Long, ByRef lpKey As Byte, ByVal nKeyLen As Long, ByVal strCustom As String, ByVal nOptions As Long) As Long
nRet = PRF_Bytes(abOutput(0), nOutBytes, abMessage(0), nMsgLen, abKey(0), nKeyLen, strCustom, nOptions)
' Note the "(0)" after the byte array parameters
long __stdcall PRF_Bytes(unsigned char *lpOutput, long nOutBytes, const void *lpMessage, long nMsgLen, const void *lpKey, long nKeyLen, const char *szCustom, long nOptions);
If successful, the return value is the number of bytes in the output; otherwise it returns a negative error code.
Public Function prfBytes (nBytes As Long, lpMessage() As Byte, lpKey() As Byte, nOptions As Long, Optional szCustom As String = "") As Byte()
static bvec_t dipki::Prf::Bytes (int numBytes, const bvec_t &message, const bvec_t &key, PrfAlg prfalg, const std::string &customStr="")
static Prf.bytes(numbytes, msg, key, prfalg, customstring="")
The output buffer lpOutput must exist. It will be filled with exactly nOutBytes bytes.
Note there is no zero option for nOptions: a valid option flag must be specified.
For KMAC, the default customization string szCustom is the empty string "".
Dim strKeyHex As String Dim strMsgHex As String Dim nOutBits As Long Dim nOutBytes As Long Dim abMAC() As Byte Dim abMsg() As Byte Dim abKey() As Byte Dim nMsgLen As Long Dim nKeyLen As Long Dim strCustom As String Dim strOK As String Dim nRet As Long ' Ref: `KMAC_samples.pdf` "Secure Hashing - KMAC-Samples" 2017-02-27 ' <https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf> ' Sample #2 ' Input in hex form strKeyHex = "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F" strMsgHex = "00010203" nOutBits = 256 strCustom = "My Tagged Application" strOK = "3B1FBA963CD8B0B59E8C1A6D71888B7143651AF8BA0A7070C0979E2811324AA5" ' Convert to byte array form abKey = cnvBytesFromHexStr(strKeyHex) abMsg = cnvBytesFromHexStr(strMsgHex) nKeyLen = UBound(abKey) + 1 nMsgLen = UBound(abMsg) + 1 ' Required output size nOutBytes = (nOutBits / 8) ReDim abMAC(nOutBytes - 1) nRet = PRF_Bytes(abMAC(0), nOutBytes, abMsg(0), nMsgLen, abKey(0), nKeyLen, strCustom, PKI_KMAC_128) If nRet > 0 Then Debug.Print "KMAC=" & cnvHexStrFromBytes(abMAC) Debug.Print "OK =" & strOK Else Debug.Print "Error code " & nRet End If
This should result in output as follows:
KMAC=3B1FBA963CD8B0B59E8C1A6D71888B7143651AF8BA0A7070C0979E2811324AA5 OK =3B1FBA963CD8B0B59E8C1A6D71888B7143651AF8BA0A7070C0979E2811324AA5
Dim lpPrf() As Byte
Dim lpMsg() As Byte
Dim lpKey() As Byte
lpKey = cnvFromHex("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")
lpMsg = cnvFromHex("00010203")
' NB order of parameters (szCustom <=> nOptions).
lpPrf = prfBytes(256 \ 8, lpMsg, lpKey, PKI_KMAC_128, "My Tagged Application")
Debug.Print "KMAC=" & cnvToHex(lpPrf)
Debug.Print "OK =3B1FBA963CD8B0B59E8C1A6D71888B7143651AF8BA0A7070C0979E2811324AA5"
Prompts for a password in a dialog box.
Public Declare Function PWD_Prompt Lib "diCrPKI.dll"
(ByVal strPassword As String, ByVal nPwdLen As Long, ByVal strCaption As String) As Long
nRet = PWD_Prompt(strPassword, nPwdLen, strCaption)
long __stdcall PWD_Prompt(char *szPassword, long nPwdLen, const char *szCaption);
If the user enters a password in the dialog box and clicks "OK", the return value is the length of the password entered in bytes. This could be zero. If the user clicks "Cancel", the return value is -1.
Public Function pwdPrompt (Optional szCaption As String = "", Optional szPrompt As String = "") As String
static std::string dipki::Pwd::Prompt (const std::string &caption, const std::string &prompt="", int maxChars=1024)
Specify a zero nOutChars or an empty string for szOutput to find the required length of the output string. ANSI C users must add one to this value when allocating memory.
The password string is limited to 255 characters. It's up to the developer to protect the secrecy of the password
once it's been entered:
see WIPE_Data().
This wrapper function can be used to return a password entered by the user in a dialog box. Note it does not distinguish between an empty password and the user clicking "Cancel".
Public Function pwdPrompt(Optional sCaption As String) As String
Dim sPassword As String
Dim nLen As Long
nLen = 255
sPassword = String(nLen, " ")
nLen = PWD_Prompt(sPassword, nLen, sCaption)
If nLen < 0 Then
Exit Function
ElseIf nLen > 0 Then
pwdPrompt = Left$(sPassword, nLen)
End If
' Clean up local variable
Call WIPE_String(sPassword, nLen)
End Function
Example to prompt for a password in C:
long pwdlen;
char password[256];
pwdlen = PWD_Prompt(password, sizeof(password)-1, "Test");
if (pwdlen >= 0)
printf("Password entered=[%s]\n", password);
else
printf("No password entered\n");
/* ... use password ... */
WIPE_Data(password, pwdlen);
Prompts for a password in a dialog box with option to change prompt wording.
Public Declare Function PWD_PromptEx Lib "diCrPKI.dll"
(ByVal strPassword As String, ByVal nPwdLen As Long, ByVal strCaption As String,
ByVal strPrompt As String, ByVal nOptions As Long) As Long
nRet = PWD_PromptEx(strPassword, nPwdLen, strCaption, strPrompt, nOptions)
long __stdcall PWD_PromptEx(char *szPassword, long nPwdLen, const char *szCaption, const char *szPrompt, long nOptions);
If the user enters a password in the dialog box and clicks "OK", the return value is the length of the password entered in bytes. This could be zero. If the user clicks "Cancel", the return value is -1.
static Pwd.prompt(caption="", prompt="")
See PWD_Prompt().
Example of PWD_PromptEx:
Dim strPassword As String * 511 Dim nLen As Long nLen = PWD_PromptEx(strPassword, Len(strPassword), _ "Demo of PWD_PromptEx", "Type secret phrase:", 0) ' Do something with the password... If nLen > 0 Then Debug.Print "Password entered=" & Left(strPassword, nLen) ElseIf nLen < 0 Then Debug.Print "User cancelled" Else Debug.Print "Empty password entered" End If ' Clean up Call WIPE_String(strPassword, nLen) strPassword = ""
Generates a random set of byte data suitable for cryptographic keys.
Public Declare Function RNG_Bytes Lib "diCrPKI.dll"
(ByRef lpData As Byte, ByVal nDataLen As Long, ByVal strSeed As String,
ByVal nSeedLen As Long) As Long
nRet = RNG_Bytes(lpData(0), nDataLen, strSeed, nSeedLen)
long __stdcall RNG_Bytes(unsigned char *lpOutput, long nOutBytes, const void *lpSeed, long nSeedLen);
If successful, the return value is zero. If the parameters are invalid, it returns a negative error code.
Public Function rngBytes (nBytes As Long) As Byte()
Rng.Bytes Method (Int32)
Rng.Bytes Method (Int32, Byte)
Rng.Bytes Method (Int32, String)
static bvec_t dipki::Rng::Bytes (int n)
static Rng.bytestring(n)
The maximum number of random bytes that can be requested in one call is 65,536 (64 kB).
If you need more (!), make repeated calls.
VB6/VBA users: for historical reasons, the seed parameter is passed as a String type
and may contain any 8-bit value including the NUL (zero) value.
The length of the seed must be specified (set nSeedLen as zero to ignore).
If the RNG fails its FIPS-140 continuous test, the DLL process will be terminated. There is no option to avoid this, but the chances of such a failure under normal conditions are absolutely miniscule - about 1 in 9 quintillion (billion billion billion). See Random Number Generator for more information on the RNG, entropy, and its compliance with the relevant standards.
Dim abData() As Byte
Dim nDataLen As Long
nDataLen = 16
ReDim abData(nDataLen - 1)
Call RNG_Bytes(abData(0), nDataLen, "", 0)
Debug.Print cnvHexStrFromBytes(abData)
Dim i As Integer
For i = 1 To 10
Debug.Print cnvHexStrFromBytes(rngBytes(32))
Next
RNG_BytesWithPrompt RNG_Number
Generates a random set of byte data suitable for cryptographic keys with a prompt for the user to enter random keystrokes and mouse movements.
Public Declare Function RNG_BytesWithPrompt Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutputLen As Long, ByVal strPrompt As String, ByVal nOptions As Long) As Long
nRet = RNG_BytesWithPrompt(lpOutput(0), nOutputLen, strPrompt, nSeedLen)
long __stdcall RNG_BytesWithPrompt(unsigned char *lpOutput, long nOutBytes, const char *szPrompt, long nOptions);
If successful, the return value is zero. If the parameters are invalid, it returns a negative error code.
Rng.BytesWithPrompt Method (Int32, Rng.Strength)
Rng.BytesWithPrompt Method (Int32, String, Rng.Strength)
static Rng.bytes_with_prompt(n, strength=Strength.BITS_112, prompt='')
Once started, there is no way to abandon the dialog that prompts the user except by terminating the process. Some applications may not handle the GUI dialog. Make your own tests to check. The maximum number of random bytes that can be requested in one call is 65,536 (64 kB). See Random Number Generator for more information on the RNG and its compliance with the relevant standards.
Dim abData() As Byte Dim nDataLen As Long ' Allocate byte array for 16 bytes nDataLen = 16 ReDim abData(nDataLen - 1) ' Default prompt with default 112-bit security strength Call RNG_BytesWithPrompt(abData(0), nDataLen, "", 0) Debug.Print cnvHexStrFromBytes(abData) ' User-selected prompt with 128-bit security strength Call RNG_BytesWithPrompt(abData(0), nDataLen, "Our own prompt: type until done...", PKI_RNG_STRENGTH_128) Debug.Print cnvHexStrFromBytes(abData)
Generate a random 36-character Global Unique IDentifier (GUID) string.
Public Declare Function RNG_Guid Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal nOptions As Long) As Long
nRet = RNG_Guid(strOutput, nOutChars, nOptions)
long __stdcall RNG_Guid(char *szOutput, long nOutChars, long nOptions);
If successful, the return value is the number of characters in or required for the output string (always 36); otherwise it returns a negative error code.
Public Function rngGuid() As String
static std::string dipki::Rng::Guid ()
static Rng.guid()
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
A Global Unique IDentifier (GUID) is also called a version 4 Universally Unique IDentifier (UUID) and is defined in section 4.4 of [RFC4122].
The output is always a 36-character string of the form "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" where 'x' is a hexadecimal digit [0-9a-f].
The constant PKI_RNG_GUID_CHARS equal to 36 is defined for convenience.
It is an error (SHORT_BUF_ERROR) if the output buffer is too short.
Dim strGuid As String
strGuid = String(PKI_RNG_GUID_CHARS, " ")
Call RNG_Guid(strGuid, Len(strGuid), 0)
Debug.Print strGuid
The output will be different each time. For example
9d67804a-4d8f-40c2-8f7d-5f05f90cb228 85291113-b97f-4d30-8892-76d556801372 fc4272a5-c731-4b96-9c7c-450fad9a29c0
Dim i As Integer
For i = 1 To 5
Debug.Print rngGuid()
Next
Initializes the RNG generator with a seed file.
Public Declare Function RNG_Initialize Lib "diCrPKI.dll" (ByVal strSeedFile As String, ByVal nOptions As Long) As Long
nRet = RNG_Initialize(strSeedFile, nOptions)
long __stdcall RNG_Initialize(const char *szSeedFile, long nOptions);
"".
If successful, the return value is zero; otherwise it returns a nonzero error code.
If "" is passed for szSeedFile, it returns the support status for Intel DRNG (see Remarks).
Public Function rngInitialize (szSeedFile As String) As Long
Public Function rngInitializeEx (Optional nOptions As Long = 0) As Long
Rng.Initialize Method
Rng.InitializeEx Method
static int dipki::Rng::Initialize (const std::string &seedFile)
static int dipki::Rng::InitializeEx (Opts opts=Opts::Default)
static Rng.initialize_ex(opts=0)
static Rng.initialize(seedfilename)
static Rng.initialize_ex(opts=0)
A seed file maintains the entropy state between sessions. If the seed file does not exist, it will be created, using any existing entropy. The file must be writable by the user. File locking is used to prevent interference from simultaneous use by others. The seed file is automatically updated by this procedure. Any existing file will be overwritten without warning.
Intel(R) DRNG support: [New in v22.1] Pass an empty string "" for szSeedFile to query support for
Intel(R) Digital Random Number Generator (DRNG) on your system (and add an extra 256 bits of entropy, if available).
If supported, the return value is a positive integer (1,2,3),
otherwise it returns the error code PRNG_ERR_NOTAVAIL (-214).
See Intel(R) DRNG.
Alternatively, use the option PKI_RNG_NO_INTEL_DRNG to turn off support for Intel(R) DRNG for the current session. You might use this if calls to Intel(R) DRNG are causing problems on your system.
This example shows how to initialize the RNG with a seed file, generate some random data, and then update the seed file.
Dim strSeedFile As String Dim nRet As Long Dim abData() As Byte Dim nDataLen As Long Dim i As Integer strSeedFile = "seed.dat" ' 1. Initialize nRet = RNG_Initialize(strSeedFile, 0) Debug.Print "RNG_Initialize('" & strSeedFile & "') returns " & nRet & " (expecting 0)" ' 2. Generate some random data nDataLen = 24 ReDim abData(nDataLen - 1) For i = 1 To 3 Call RNG_Bytes(abData(0), nDataLen, "", 0) Debug.Print cnvHexStrFromBytes(abData) Next ' 3. Update the seed file nRet = RNG_UpdateSeedFile(strSeedFile, 0) Debug.Print "RNG_UpdateSeedFile('" & strSeedFile & "') returns " & nRet & " (expecting 0)"
RNG_Initialize('seed.dat') returns 0 (expecting 0)
79654D8DA3D30468B95B820E3C5615838A765CA666C68A9D
EB2DA20FC86CC797BCB3D26C9E663736E616EF99DEB56C21
5A3DB035BD374E57649AEE367A7E0156A3045AE0111D47EC
RNG_UpdateSeedFile('seed.dat') returns 0 (expecting 0)
This example demonstrates support for Intel(R) DRNG
Dim n As Long n = RNG_Initialize("", 0) ' Query support for Intel(R) DRNG Debug.Print "RNG_Initialize() returns " & n & " (If > 0 Intel(R) DRNG support available)" ' Explicitly turn off support... n = RNG_Initialize("", PKI_RNG_NO_INTEL_DRNG) ' Turns off Intel(R) DRNG support Debug.Print "RNG_Initialize(PKI_RNG_NO_INTEL_DRNG) returns " & n & " (expected -ve)" n = RNG_Initialize("", 0) ' Now query again Debug.Print "RNG_Initialize() returns " & n & " (expected -ve)"
RNG_Initialize() returns 3 (If > 0 Intel(R) DRNG support available) RNG_Initialize(PKI_RNG_NO_INTEL_DRNG) returns -214 (expected -ve) RNG_Initialize() returns -214 (expected -ve)
In practice, you should test for Intel(R) DRNG support before calling any RNG function. If supported, then the generator will have been seeded with sufficient entropy. If not supported, then use a seed file.
Dim n As Long n = rngInitializeEx() If n <= 0 Then ' Use a seed file n = rngInitialize("seed.dat") End If ' Do work... Dim abKey() As Byte abKey = rngBytes(32) Debug.Print cnvToHex(abKey) ' ...etc ' At end of session, update the seed file n = RNG_UpdateSeedFile("seed.dat", 0)
RNG_MakeSeedFile RNG_UpdateSeedFile
Creates a new seed file suitable for use with
RNG_Initialize().
Public Declare Function RNG_MakeSeedFile Lib "diCrPKI.dll" (ByVal strSeedFile As String, ByVal strPrompt As String, ByVal nOptions As Long) As Long
nRet = RNG_MakeSeedFile(strSeedFile, strPrompt, nOptions)
long __stdcall RNG_MakeSeedFile(const char *szSeedFile, const char *szPrompt, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
static Rng.make_seedfile(seedfilename, strength=Strength.BITS_128, prompt='')
This uses a dialog window and expects the user to type in random keystrokes.
Such a GUI interface may not be appropriate in all circumstances.
A new seed file is always created. Any existing file with the same name will be overwritten without warning.
Alternatively, use the command-line program, PkiMkRngSeed.exe, provided in the distribution
to make a new seed file [updated in v22.1].
Dim strSeedFile As String
Dim nRet As Long
strSeedFile = "seed.dat"
nRet = RNG_MakeSeedFile(strSeedFile, "Making a new seed file: hit random keys until done...", PKI_RNG_STRENGTH_128)
Debug.Print "RNG_MakeSeedFile('" & strSeedFile & "') returns " & nRet & " (expecting 0)"
RNG_Initialize RNG_UpdateSeedFile
Returns an integer selected at random between specified limits.
Public Declare Function RNG_Number Lib "diCrPKI.dll"
(ByVal nLower As Long, ByVal nUpper As Long) As Long
nRandom = RNG_Number(nLower, nUpper)
long __stdcall RNG_Number(long nLower, long nUpper);
An integer selected at random from the set {nLower, ..., nUpper}.
Rng.Number Method
Rng.Octet Method
static int dipki::Rng::Number (int lower, int upper)
static Rng.octet()
static Rng.number(lower, upper)
static Rng.octet()
The number returned is an integer selected at random with uniform probability from the set {nLower, ..., nUpper}.
This will generate 5 random numbers in the range between -1 million and +1 million:
Dim i As Integer
For i = 1 To 5
Debug.Print RNG_Number(-1000000, 1000000)
Next
This will generate 16 random bits in [0,1]:
Dim i As Integer
For i = 1 To 16
Debug.Print RNG_Number(0, 1);
Next
Debug.Print
0 0 0 1 0 0 1 1 0 1 1 1 0 0 1 1
A function to generate a random octet (byte).
Public Function rngOctet() As Byte rngOctet = RNG_Number(0, 255) End Function
This will generate 8 random octets (bytes):
Dim i As Integer
For i = 1 To 8
Debug.Print rngOctet();
Next
Debug.Print
6 131 87 118 57 252 240 33
Generates a string of random characters (classic VB6/VBA only).
Public Declare Function RNG_String Lib "diCrPKI.dll" Alias "RNG_Bytes"
(ByVal strData As String, ByVal nDataLen As Long, ByVal strSeed As String,
ByVal nSeedLen As Long) As Long
nRet = RNG_String(strData, nDataLen, strSeed, nSeedLen)
[Not applicable]
If successful, the return value is zero; otherwise it returns a nonzero error code.
Not applicable
@deprecated. This is an alias for classic Visual Basic (VB6/VBA) users only. The output string may contain characters with value zero (and possibly traces of nuts). Storing binary information in a string is bad practice. This function was provided for one specific purpose and is deprecated. See Random Number Generator for more information on the RNG and seeds.
Generate a string of random characters with a prompt (classic VB6/VBA only).
Public Declare Function RNG_StringWithPrompt Lib "diCrPKI.dll" Alias "RNG_BytesWithPrompt"
(ByVal strData As String, ByVal nDataLen As Long, ByVal strPrompt As String, ByVal nOptions As Long) As Long
nRet = RNG_StringWithPrompt(strData, nDataLen, strPrompt, nOptions)
[Not applicable]
If successful, the return value is zero; otherwise it returns a nonzero error code.
Not applicable
@deprecated. This is an alias for classic Visual Basic (VB6/VBA) users only. The output string may contain characters with value zero (and possibly traces of nuts). See Random Number Generator for more information on the RNG and seeds.
Carries out a NIST SP800-90 health check and FIPS140-2 statistical tests on the random number generator.
Public Declare Function RNG_Test Lib "diCrPKI.dll" (ByVal strFileName As String, ByVal nOptions As Long) As Long
nRet = RNG_Test(strFileName, nOptions)
long __stdcall RNG_Test(const char *szFileOut, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
This function carries out, on demand, the health testing procedure from section 11.3 of
[SP80090A] and the statistical tests for randomness from
section 4.9.1 of the October 2001 version of FIPS-140-2 [FIPS140].
The statistical test results and the 20,000-bit sample are written to a text file.
Specify an empty ("") or NULL szFileName to avoid creating an output file and just
carry out the tests. The statistical tests have since been removed from FIPS-140-2, but we do them anyway.
If any tests fail, a nonzero error code will be returned.
Dim strFileName As String
Dim nRet As Long
strFileName = "pkiFips140.txt"
nRet = RNG_Test(strFileName, 0)
Debug.Print "RNG_Test('" & strFileName & "') returns " & nRet & " (expecting 0)"
Test the RNG for conformance to NIST SP800-90A using the relevant test specified in DRBGVS.
Public Declare Function RNG_TestDRBGVS Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nMaxChars As Long, ByVal nReturnedBitsLen As Long, ByVal strEntropyInput As String, ByVal strNonce As String, ByVal strPersonalizationString As String, ByVal strAdditionalInput1 As String, ByVal strEntropyReseed As String, ByVal strAdditionalInputReseed As String, ByVal strAdditionalInput2 As String, ByVal nOptions As Long) As Long
nRet = RNG_TestDRBGVS(strOutput, nMaxChars, nReturnedBitsLen, strEntropyInput, strNonce, strPersonalizationString, strAdditionalInput1, strEntropyReseed, strAdditionalInputReseed, strAdditionalInput2, nOptions)
long __stdcall RNG_TestDRBGVS(char *szOutput, long nMaxChars, long nReturnedBitsLen, const char *szEntropyInput,
const char *szNonce, const char *szPersonalizationString, const char *szAdditionalInput1,
const char *szEntropyReseed, const char *szAdditionalInputReseed, const char *szAdditionalInput2, long nOptions);
If successful, the return value is the number of characters in the output string; otherwise it returns a negative error code.
static Rng.test_drbgvs(returnedBitsLen, entropyInput, nonce, personalizationString, additionalInput1, entropyReseed, additionalInputReseed, additionalInput2)
The test procedure, the input values and the expected output are described in the [DRBGVS] document and associated test vectors.
The relevant DRBG mechanism is HMAC_DRBG SHA-512 without prediction resistance.
Use the empty string "" to pass a zero-length input. All hex strings must have an even number of characters.
' drbgtestvectors/drbgvectors_pr_false/HMAC_DRBG.txt (line 22654) ' # CAVS 14.3 ' # DRBG800-90A information for "drbg_pr" ' # Generated on Tue Apr 02 15:32:12 2013 Dim nRet As Long Dim strOutput As String Dim nMaxChars As Long ' Set input values in hex Const nReturnedBitsLen As Long = 2048 Const strEntropyInput As String = "da740cbc36057a8e282ae717fe7dfbb245e9e5d49908a0119c5dbcf0a1f2d5ab" Const strNonce As String = "46561ff612217ba3ff91baa06d4b5440" Const strPersonalizationString As String = "fc227293523ecb5b1e28c87863626627d958acc558a672b148ce19e2abd2dde4" Const strAdditionalInput1 As String = "b7998998eaf9e5d34e64ff7f03de765b31f407899d20535573e670c1b402c26a" Const strEntropyReseed As String = "1d61d4d8a41c3254b92104fd555adae0569d1835bb52657ec7fbba0fe03579c5" Const strAdditionalInputReseed As String = "b9ed8e35ad018a375b61189c8d365b00507cb1b4510d21cac212356b5bbaa8b2" Const strAdditionalInput2 As String = "2089d49d63e0c4df58879d0cb1ba998e5b3d1a7786b785e7cf13ca5ea5e33cfd" Const strExpectedBits = "5b70f3e4da95264233efbab155b828d4e231b67cc92757feca407cc9615a6608" & _ "71cb07ad1a2e9a99412feda8ee34dc9c57fa08d3f8225b30d29887d20907d123" & _ "30fffd14d1697ba0756d37491b0a8814106e46c8677d49d9157109c402ad0c24" & _ "7a2f50cd5d99e538c850b906937a05dbb8888d984bc77f6ca00b0e3bc97b16d6" & _ "d25814a54aa12143afddd8b2263690565d545f4137e593bb3ca88a37b0aadf79" & _ "726b95c61906257e6dc47acd5b6b7e4b534243b13c16ad5a0a1163c0099fce43" & _ "f428cd27c3e6463cf5e9a9621f4b3d0b3d4654316f4707675df39278d5783823" & _ "049477dcce8c57fdbd576711c91301e9bd6bb0d3e72dc46d480ed8f61fd63811" ' Print output details Debug.Print "# HMAC_DRBG options: SHA-512" Debug.Print "[SHA-512]" Debug.Print "[PredictionResistance = False]" Debug.Print "[EntropyInputLen = " & Len(strEntropyInput) * 8 / 2 & "]" Debug.Print "[NonceLen = " & Len(strNonce) * 8 / 2 & "]" Debug.Print "[PersonalizationStringLen = " & Len(strPersonalizationString) * 8 / 2 & "]" Debug.Print "[AdditionalInputLen = " & Len(strAdditionalInput1) * 8 / 2 & "]" Debug.Print Debug.Print "COUNT = 0" Debug.Print "EntropyInput = " & strEntropyInput Debug.Print "Nonce = " & strNonce Debug.Print "PersonalizationString = " & strPersonalizationString Debug.Print "AdditionalInput = " & strAdditionalInput1 Debug.Print "EntropyInputReseed = " & strEntropyReseed Debug.Print "AdditionalInputReseed = " & strAdditionalInputReseed Debug.Print "AdditionalInput = " & strAdditionalInput2 ' Perform the DRBGVS test, dimensioning output string first strOutput = String(nReturnedBitsLen * 2 / 8, " ") nRet = RNG_TestDRBGVS(strOutput, Len(strOutput), nReturnedBitsLen, strEntropyInput, strNonce, _ strPersonalizationString, strAdditionalInput1, _ strEntropyReseed, strAdditionalInputReseed, strAdditionalInput2, 0) Debug.Print "ReturnedBits = " & strOutput Debug.Print "ExpectedBits = " & strExpectedBits Debug.Assert strOutput = strExpectedBits
# HMAC_DRBG options: SHA-512 [SHA-512] [PredictionResistance = False] [EntropyInputLen = 256] [NonceLen = 128] [PersonalizationStringLen = 256] [AdditionalInputLen = 256] COUNT = 0 EntropyInput = da740cbc36057a8e282ae717fe7dfbb245e9e5d49908a0119c5dbcf0a1f2d5ab Nonce = 46561ff612217ba3ff91baa06d4b5440 PersonalizationString = fc227293523ecb5b1e28c87863626627d958acc558a672b148ce19e2abd2dde4 AdditionalInput = b7998998eaf9e5d34e64ff7f03de765b31f407899d20535573e670c1b402c26a EntropyInputReseed = 1d61d4d8a41c3254b92104fd555adae0569d1835bb52657ec7fbba0fe03579c5 AdditionalInputReseed = b9ed8e35ad018a375b61189c8d365b00507cb1b4510d21cac212356b5bbaa8b2 AdditionalInput = 2089d49d63e0c4df58879d0cb1ba998e5b3d1a7786b785e7cf13ca5ea5e33cfd ReturnedBits = 5b70f3e4da95264233efbab155b828d4e231b67cc92757feca407cc9615a6608... ExpectedBits = 5b70f3e4da95264233efbab155b828d4e231b67cc92757feca407cc9615a6608...
Updates an RNG seed file.
Public Declare Function RNG_UpdateSeedFile Lib "diCrPKI.dll" (ByVal strSeedFile As String, ByVal nOptions As Long) As Long
nRet = RNG_UpdateSeedFile(strSeedFile, nOptions)
long __stdcall RNG_UpdateSeedFile(const char *szSeedFile, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
static int dipki::Rng::UpdateSeedFile (const std::string &seedFile)
static Rng.update_seedfile(seedfilename)
This writes a fresh set of random data to the seed file. The seed file must be writable by the user. Use this function at periodic intervals or when exiting your application. If the file does not exist it will be created. Any existing file of the same name will be overwritten without warning.
See the example in RNG_Initialize.
RNG_Initialize RNG_MakeSeedFile
Checks if an RSA key is valid.
Public Declare Function RSA_CheckKey Lib "diCrPKI.dll"
(ByVal strKeyString As String,
ByVal nOptions As Long) As Long
nRet = RSA_CheckKey(strKeyString, nOptions)
long __stdcall RSA_CheckKey(const char *szKeyString, long nOptions);
If successful, the return value is PKI_VALID_PRIVATEKEY (0)
if the key is a valid private key, or PKI_VALID_PUBLICKEY (1) if the key is a public key;
otherwise it returns a negative error code.
Rsa.CheckKey Method (String)
Rsa.CheckKey Method (StringBuilder)
static bool dipki::Rsa::KeyIsPrivate (const std::string &keyStr)
static Rsa.key_isprivate(keystr)
If the key is a private key, the system carries out a pairwise check using a random message block to verify that the key is a valid RSA key pair (the format used to store private keys contains both the public and private components). Such a check cannot be carried out with a public key.
See RSA_FromXMLString.
RSA_KeyBits RSA_KeyBytes RSA_KeyHashCode
Decodes an EME or EMSA encoded message block according to PKCS#1 (EME = Encoding Method for Encryption, EMSA = Encoding Method for Signature with Appendix).
Public Declare Function RSA_DecodeMsg Lib "diCrPKI.dll"
(ByRef lpOutput As Byte, ByVal nOutChars As Long,
ByRef lpInput As Byte, ByVal nInputLen As Long,
ByVal nOptions As Long) As Long
nRet = RSA_DecodeMsg(lpOutput(0), nOutputLen, lpInput(0), nInputLen, nOptions)
long __stdcall RSA_DecodeMsg(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpInput, long nInputLen, long nOptions);
If you have selected PKI_EMSIG_PKCSV1_5, then you can add:
PKI_EMSIG_DIGINFO to decode an 'Encoded Message for Signature' block
and output the whole DigestInfo data instead of just the message digest.
If you have selected PKI_EME_OAEP, then add one of these options to match the hash function used for EME-OAEP encoding:
PKI_HASH_SHA1 (0) to use SHA-1 (default).
PKI_HASH_SHA224 to use SHA-224
PKI_HASH_SHA256 to use SHA-256
PKI_HASH_SHA384 to use SHA-384
PKI_HASH_SHA512 to use SHA-512
and, optionally, add:-
PKI_MGF_MGF1SHA1 to force the MGF hash function to be SHA-1 (default = same as encoding hash function set above)
The encoding hash function and MGF hash function must match the hash functions used to encode the message.
Alternatively, ignore all the above and use the specialist option
PKI_EMSIG_ISO9796 to use the ISO9796-1 encoding for a signature. See
AUTACK messages and ISO/IEC 9796-1 signatures for more details.
If successful, the return value is the number of bytes required to store the full output data. If an error occurs, it returns a negative error code.
Public Function rsaDecodeMsg (lpInput() As Byte, nOptions As Long) As Byte()
Rsa.DecodeMsgForEncryption Method
Rsa.DecodeDigestForSignature Method
Rsa.DecodeMsgIso9796 Method
static Rsa.decode_msg_for_encryption(data, method=EME.PKCSV1_5)
static Rsa.decode_digest_for_signature(data, full_digestinfo=False)
static Rsa.decode_msg_for_encryption(data, method=EME.PKCSV1_5)
This function recovers the relevant data from an encoded message block according to the algorithms in PKCS#1.
Messages encoded for both encryption and signature using the PKCS#1 v1.5 method are self-contained: that is, they can be decoded with no further information other than the encoded message itself. However, a message encoded using the OAEP method will be assumed by default to have been encoded using the default SHA-1 function for both the encoding hash algorithm and MGF hash algorithm. If you used a different hash function when encoding you need to specify it explicitly in nOptions.
The algorithm RSA-PSS is not available for this function. Use SIG_VerifyData instead.
The objective is to recover the original message data which is encoded in the block. Use either
nOptions = PKI_EME_PKCSV1_5
or
nOptions = PKI_EME_OAEP
You need to know which algorithm was used to create the block in the first place.
The objective is to verify that the encoded message digest hash matches the message digest hash of the original message.
RSA_EncodeMsg()
function on the original message
and then compare the result of that with the input block you have here. See Raw RSA Techniques.
The options here are included for advanced users.
There are two choices when decoding an EMSA block:
nOptions = PKI_EMSIG_PKCSV1_5
DigestInfo bytes.
Set
nOptions = PKI_EMSIG_PKCSV1_5 + PKI_EMSIG_DIGINFOYou might use this if you come across a hash algorithm that is not supported by this Toolkit. Use this option to recover the entire
DigestInfo and then inspect the bytes to work out what it is, using your knowledge of DER encoding.
Remember that the result of a decode operation for a signature is to compare the hash digest encoded in the signature with an independent digest of the original message. If they match, the signature is verified. To avoid an attacker exploiting flaws in the decoding operation, it is safer just to generate another EMSA block from the message and compare that directly.
Dim abData() As Byte
Dim abBlock() As Byte
Dim abDigest() As Byte
Dim abDigInfo() As Byte
Dim nDataLen As Long
Dim nBlockLen As Long
Dim nLen As Long
Dim nRet As Long
Dim nOptions As Long
' 0. Create an encoded test block ready for for signing
abData = StrConv("abc", vbFromUnicode)
nDataLen = UBound(abData) - LBound(abData) + 1
nBlockLen = 64
ReDim abBlock(nBlockLen - 1)
nRet = RSA_EncodeMsg(abBlock(0), nBlockLen, abData(0), nDataLen, PKI_EMSIG_PKCSV1_5)
Debug.Print "BLOCK =" & cnvHexStrFromBytes(abBlock)
' 1. Extract the message digest =SHA1("abc")
nLen = RSA_DecodeMsg(0, 0, abBlock(0), nBlockLen, PKI_EMSIG_PKCSV1_5)
If nLen < 0 Then MsgBox "Decryption Error": Exit Function
Debug.Print "Message digest is " & nLen & " bytes long"
ReDim abDigest(nLen - 1)
nLen = RSA_DecodeMsg(abDigest(0), nLen, abBlock(0), nBlockLen, PKI_EMSIG_PKCSV1_5)
Debug.Print "HASH =" & cnvHexStrFromBytes(abDigest)
' 2. Extract the full DigestInfo data
nOptions = PKI_EMSIG_PKCSV1_5 + PKI_EMSIG_DIGINFO
nLen = RSA_DecodeMsg(0, 0, abBlock(0), nBlockLen, nOptions)
If nLen < 0 Then MsgBox "Decryption Error": Exit Function
Debug.Print "DigestInfo is " & nLen & " bytes long"
ReDim abDigest(nLen - 1)
nLen = RSA_DecodeMsg(abDigest(0), nLen, abBlock(0), nBlockLen, nOptions)
Debug.Print "DIGINFO=" & cnvHexStrFromBytes(abDigest)
This should produce results like:
BLOCK =0001FFFFFF...C26C9CD0D89D Message digest is 20 bytes long HASH =A9993E364706816ABA3E25717850C26C9CD0D89D DigestInfo is 35 bytes long DIGINFO=3021300906052B0E03021A05000414A9993E364706816ABA3E25717850C26C9CD0D89D
Dim lpData() As Byte
Dim lpBlock() As Byte
Dim lpDecoded() As Byte
Dim nBlockLen As Long
nBlockLen = 512 \ 8
lpData = cnvBytesFromHexStr("DEADBEEF")
lpBlock = rsaEncodeMsg(nBlockLen, lpData, PKI_EME_PKCSV1_5)
Debug.Print cnvHexStrFromBytes(lpBlock)
lpDecoded = rsaDecodeMsg(lpBlock, PKI_EME_PKCSV1_5)
Debug.Print "DECODED=" & cnvHexStrFromBytes(lpDecoded)
lpBlock = rsaEncodeMsg(nBlockLen, lpData, PKI_EME_OAEP)
Debug.Print cnvHexStrFromBytes(lpBlock)
lpDecoded = rsaDecodeMsg(lpBlock, PKI_EME_OAEP)
Debug.Print "DECODED=" & cnvHexStrFromBytes(lpDecoded)
lpBlock = rsaEncodeMsg(nBlockLen, lpData, PKI_EMSIG_PKCSV1_5 Or PKI_HASH_SHA256)
Debug.Print cnvHexStrFromBytes(lpBlock)
lpDecoded = rsaDecodeMsg(lpBlock, PKI_EMSIG_PKCSV1_5)
Debug.Print "DECODED=" & cnvHexStrFromBytes(lpDecoded)
Debug.Print "DIGEST =" & hashHexFromBytes(lpData, PKI_HASH_SHA256)
RSA_EncodeMsg RSA_RawPublic RSA_RawPrivate Raw RSA Techniques
Decrypt a message encrypted using an RSA encryption scheme.
Public Declare Function RSA_Decrypt Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpInput As Byte, ByVal nInputLen As Long, ByVal strPrivateKeyFile As String, ByVal strPassword As String, ByVal strParameters As String, ByVal nOptions As Long) As Long
nRet = RSA_Decrypt(lpOutput(0), nOutBytes, lpInput(0), nInputLen, strPrivateKeyFile, strPassword, strParameters, nOptions)
long __stdcall RSA_Decrypt(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpInput, long nInputLen, const char *szPrivateKeyFile, const char *szPassword, const char *szParameters, long nOptions);
"" if password is not required."".
If you have selected PKI_EME_OAEP, then add one of these options to set the hash function used for EME-OAEP encoding:
PKI_HASH_SHA1 (0) to use SHA-1 (default).
PKI_HASH_SHA224 to use SHA-224
PKI_HASH_SHA256 to use SHA-256
PKI_HASH_SHA384 to use SHA-384
PKI_HASH_SHA512 to use SHA-512
and, optionally, add:-
PKI_MGF_MGF1SHA1 to force the MGF hash function to be SHA-1 (default = same as encoding hash function set above)
If successful, the return value is the number of bytes required to store the full output data. If an error occurs, it returns a negative error code.
Public Function rsaDecrypt (lpInput() As Byte, szPrivateKeyFile As String, szPassword As String, nOptions As Long, Optional szParameters As String = "") As Byte()
static bvec_t dipki::Rsa::Decrypt (const bvec_t &data, const std::string &privateKeyFileOrString, const std::string &password="", EME method=EME::PKCSv1_5, HashAlg hashAlg=HashAlg::Sha1, AdvOpts advOpts=AdvOpts::Default)
static Rsa.decrypt(data, prikeyfileorstring, password="", method=EME.PKCSV1_5, hashalg=HashAlg.SHA1, advopts=AdvOpts.DEFAULT)
Set nOutBytes to zero and/or lpOutput to 0 (or NULL) to return the required number of bytes.
The output will always be shorter than the input length.
For RSA-OAEP you must set the correct options to match the parameters used for the encryption. For more details see RSA encryption and signature schemes.
See RSA_Encrypt.
See example for VBA wrapper rsaEncrypt in RSA_Encrypt.
RSA_Encrypt RSA_DecodeMsg RSA_RawPrivate
Creates an EME or EMSA encoded message block according to PKCS#1 (EME = Encoding Method for Encryption, EMSA = Encoding Method for Signature with Appendix).
Public Declare Function RSA_EncodeMsg Lib "diCrPKI.dll"
(ByRef lpOutput As Byte, ByVal nOutputLen As Long,
ByRef lpMessage As Byte, ByVal nMsgLen As Long,
ByVal nOptions As Long) As Long
nRet = RSA_EncodeMsg(lpOutput(0), nOutputLen, lpMessage(0), nMsgLen, nOptions)
long __stdcall RSA_EncodeMsg(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpInput, long nInputLen, long nOptions);
If you have selected PKI_EMSIG_PKCSV1_5, then add one of these options to set the hash function for the signature message digest:
PKI_HASH_SHA1 (0) to use SHA-1 (default).
PKI_HASH_SHA224 to use SHA-224
PKI_HASH_SHA256 to use SHA-256
PKI_HASH_SHA384 to use SHA-384
PKI_HASH_SHA512 to use SHA-512
PKI_HASH_MD5 to use MD5 [legacy, not recommended]
PKI_HASH_MD2 to use MD2 [legacy, definitely not recommended]
and, optionally, add:-
PKI_EMSIG_DIGESTONLY as a flag to pass the message digest only as input to-be-signed (default = pass entire message)
If you have selected PKI_EME_OAEP, then add one of these options to set the hash function for EME-OAEP encoding:
PKI_HASH_SHA1 (0) to use SHA-1 (default).
PKI_HASH_SHA224 to use SHA-224
PKI_HASH_SHA256 to use SHA-256
PKI_HASH_SHA384 to use SHA-384
PKI_HASH_SHA512 to use SHA-512
and, optionally, add:-
PKI_MGF_MGF1SHA1 to force the MGF hash function to be SHA-1 (default = same as encoding hash function set above)
Alternatively, ignore all the above and use the specialist option
PKI_EMSIG_ISO9796 to use the ISO9796-1 encoding for a signature. See
AUTACK messages and ISO/IEC 9796-1 signatures for more details.
If successful, the return value is zero; otherwise it returns a negative error code.
CAUTION: This function assumes you know the required length of the output. It does not return the length.
Public Function rsaEncodeMsg (nBlockLen As Long, lpInput() As Byte, nOptions As Long) As Byte()
Rsa.EncodeMsgForEncryption Method
Rsa.EncodeMsgForSignature Method
Rsa.EncodeDigestForSignature Method
Rsa.EncodeMsgIso9796 Method
static Rsa.encode_msg_for_encryption(keybytes, message, method=EME.PKCSV1_5)
static Rsa.encode_msg_for_signature(keybytes, message, hashalg=HashAlg.SHA1, digest_only=False)
static Rsa.encode_msg_for_encryption(keybytes, message, method=EME.PKCSV1_5)
There are two distinct operations available here (a design decision that we regret, in hindsight). One operation creates an 'Encoded Message for Encryption' (EME) block which you would then encrypt with an RSA public key using the RSA_RawPublic() function. The other creates an 'Encoded Message for Signature with Appendix' (EMSA) block which you would then sign by encrypting with an RSA private key using the RSA_RawPrivate() function.
Set either
nOptions = PKI_EME_PKCSV1_5
or
nOptions = PKI_EME_OAEP
The default operation PKI_EME_PKCSV1_5 will create an encoded EME message block according to
PKCS#1 v1.5. The PKI_EME_OAEP alternative uses a more secure algorithm
(OAEP = Optimal Asymmetric Encryption Padding).
To encode the message "Hello world" ready for signing, use the PKI_EMSIG_PKCSV1_5 option and set
nOptions = PKI_EMSIG_PKCSV1_5
abInput = StrConv("Hello world", vbFromUnicode)
nInputLen = UBound(abMessage) - LBound(abMessage) + 1
nOptions = PKI_EMSIG_PKCSV1_5; input = "Hello world"; nInputLen = strlen(input);
If you need to be compatible with a legacy application that uses, say, MD5, add the hash flag to the option
nOptions = PKI_EMSIG_PKCSV1_5 + PKI_HASH_MD5
If you have already computed the message digest in byte array form, then pass this as input and set
nOptions = PKI_EMSIG_PKCSV1_5 + PKI_EMSIG_DIGESTONLY
The algorithm RSA-PSS is not available for this function. Use SIG_SignData instead.
Dim abData(3) As Byte Dim abBlock() As Byte Dim abCheck() As Byte Dim nDataLen As Long Dim nBlockLen As Long Dim nLen As Long Dim nRet As Long ' Our message data, 4 bytes long abData(0) = &HDE abData(1) = &HAD abData(2) = &HBE abData(3) = &HEF nDataLen = 4 Debug.Print "DATA =" & cnvHexStrFromBytes(abData) ' Set up output block with correct size nBlockLen = 64 ReDim abBlock(nBlockLen - 1) ' Encode ready for encryption with default algorithm nRet = RSA_EncodeMsg(abBlock(0), nBlockLen, abData(0), nDataLen, PKI_EME_PKCSV1_5) If (nRet < 0) Then MsgBox "Encoding Error" Exit Function End If Debug.Print "BLOCK =" & cnvHexStrFromBytes(abBlock) ' Now encrypt this block using RSA_RawPublic ' ... ' ... and send to recipient ... ' ... ' who decrypts using RSA_RawPrivate to get the encoded block ' Recover the message from the encoded block ' How long is it? nLen = RSA_DecodeMsg(0, 0, abBlock(0), nBlockLen, PKI_EME_PKCSV1_5) If (nLen < 0) Then MsgBox "Decryption Error" Exit Function End If ReDim abCheck(nLen - 1) nLen = RSA_DecodeMsg(abCheck(0), nLen, abBlock(0), nBlockLen, PKI_EME_PKCSV1_5) Debug.Print "DECODED=" & cnvHexStrFromBytes(abCheck) ' Alternative using more-secure OAEP algorithm nRet = RSA_EncodeMsg(abBlock(0), nBlockLen, abData(0), nDataLen, PKI_EME_OAEP) If (nRet < 0) Then MsgBox "Encoding Error" Exit Function End If Debug.Print "BLOCK =" & cnvHexStrFromBytes(abBlock) ' ... nLen = RSA_DecodeMsg(0, 0, abBlock(0), nBlockLen, PKI_EME_OAEP) If (nLen < 0) Then MsgBox "Decryption Error" Exit Function End If ReDim abCheck(nLen - 1) nLen = RSA_DecodeMsg(abCheck(0), nLen, abBlock(0), nBlockLen, PKI_EME_OAEP) Debug.Print "DECODED=" & cnvHexStrFromBytes(abCheck)
More detailed examples are given in the section Raw RSA Techniques.
Dim lpData() As Byte
Dim lpBlock() As Byte
Dim lpDecoded() As Byte
Dim nBlockLen As Long
nBlockLen = 512 \ 8
lpData = cnvBytesFromHexStr("DEADBEEF")
lpBlock = rsaEncodeMsg(nBlockLen, lpData, PKI_EME_PKCSV1_5)
Debug.Print cnvHexStrFromBytes(lpBlock)
lpDecoded = rsaDecodeMsg(lpBlock, PKI_EME_PKCSV1_5)
Debug.Print "DECODED=" & cnvHexStrFromBytes(lpDecoded)
lpBlock = rsaEncodeMsg(nBlockLen, lpData, PKI_EME_OAEP)
Debug.Print cnvHexStrFromBytes(lpBlock)
lpDecoded = rsaDecodeMsg(lpBlock, PKI_EME_OAEP)
Debug.Print "DECODED=" & cnvHexStrFromBytes(lpDecoded)
lpBlock = rsaEncodeMsg(nBlockLen, lpData, PKI_EMSIG_PKCSV1_5 Or PKI_HASH_SHA256)
Debug.Print cnvHexStrFromBytes(lpBlock)
lpDecoded = rsaDecodeMsg(lpBlock, PKI_EMSIG_PKCSV1_5)
Debug.Print "DECODED=" & cnvHexStrFromBytes(lpDecoded)
Debug.Print "DIGEST =" & hashHexFromBytes(lpData, PKI_HASH_SHA256)
RSA_DecodeMsg RSA_RawPublic RSA_RawPrivate Raw RSA Techniques
Encrypt a short message using RSA encryption.
Public Declare Function RSA_Encrypt Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpInput As Byte, ByVal nInputLen As Long, ByVal strPublicKeyFile As String, ByVal strParameters As String, ByVal nOptions As Long) As Long
nRet = RSA_Encrypt(lpOutput(0), nOutBytes, lpInput(0), nInputLen, strPublicKeyFile, strParameters, nOptions)
long __stdcall RSA_Encrypt(unsigned char *lpOutput, long nOutBytes, const unsigned char *lpInput, long nInputLen, const char *szPublicKeyFile, const char *szParameters, long nOptions);
"". See remarks.
If you have selected PKI_EME_OAEP, then add one of these options to set the hash function for EME-OAEP encoding:
PKI_HASH_SHA1 (0) to use SHA-1 (default).
PKI_HASH_SHA224 to use SHA-224
PKI_HASH_SHA256 to use SHA-256
PKI_HASH_SHA384 to use SHA-384
PKI_HASH_SHA512 to use SHA-512
and, optionally, add:-
PKI_MGF_MGF1SHA1 to force the MGF hash function to be SHA-1 (default = same as encoding hash function set above)
If successful, the return value is the number of bytes required to store the full output data. If an error occurs, it returns a negative error code.
Public Function rsaEncrypt (lpInput() As Byte, szPublicKeyFile As String, Optional nOptions As Long = 0, Optional szParameters As String = "") As Byte()
static bvec_t dipki::Rsa::Encrypt (const bvec_t &data, const std::string &publicKeyFileOrString, EME method=EME::PKCSv1_5, HashAlg hashAlg=HashAlg::Sha1, AdvOpts advOpts=AdvOpts::Default, const std::string ¶ms="")
static Rsa.encrypt(data, pubkeyfileorstring, method=EME.PKCSV1_5, hashalg=HashAlg.SHA1, advopts=AdvOpts.DEFAULT, params="")
Set nOutBytes to zero and/or lpOutput to 0 (or NULL) to return the required number of bytes.
The output is always the same length in bytes as the RSA modulus, which can be found directly using the RSA_KeyBytes() function.
There is a limit on the length of data that can be encrypted. For RSAES-PKCS1-V1_5, nInputLen must not be greater than the key length in bytes (k) minus 11.
For RSAES-OAEP, nInputLen must not be greater than k - 2*hLen - 2, where hLen is the length in bytes of the hash function output.
Note this means, for example, that you cannot use SHA-512 with a 1024-bit RSA key with RSAES-OAEP.
The default parameters for RSA-OAEP encoding are
hashAlgorithm = sha1, maskGenAlgorithm = mgf1SHA1 (MGF1 with SHA-1) pSourceAlgorithm =pSpecifiedEmpty (label L is the empty string)
You can change the hash algorithm using nOptions (and by default the MGF1 hash algorithm will be the same), and you can force the MGF1 hash algorithm to be SHA-1. You cannot change the mask generation algorithm (there isn't another!) or the pSourceAlgorithm parameter (i.e. the label is always the empty string). For more details see RSA encryption and signature schemes.
To carry out tests against known test vectors, you can pass a fixed seed value in szParameters. For example,
"seed=18b776ea21069d69776a33e96bad48e1dda0a5ef". This string must begin with "seed=" and be followed by the
seed value in hexadecimal encoding. This must represent a byte array of exactly hLen bytes, the length of the output of the hash function.
Dim strPriKeyFile As String Dim strPubKeyFile As String Dim abMsg() As Byte Dim nMsgLen As Long Dim abEnc() As Byte Dim nEncLen As Long Dim abDec() As Byte Dim nDecLen As Long Dim strOkHex As String ' RSAES-OAEP Encryption Example 1.1 from `oaep-vect.txt` in `pkcs-1v2-1-vec.zip` ' RSA key file 1024-bit strPubKeyFile = "rsa-oaep-1.pub" strPriKeyFile = "rsa-oaep-1.p8" ' Message to be encrypted: abMsg = cnvBytesFromHexStr("6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34") nMsgLen = UBound(abMsg) + 1 Debug.Print "MSG=" & cnvHexStrFromBytes(abMsg) ' 1. Encrypt using RSA-OAEP but set seed to be a fixed value to compare with test vector nEncLen = RSA_Encrypt(0, 0, abMsg(0), nMsgLen, strPubKeyFile, "seed=18b776ea21069d69776a33e96bad48e1dda0a5ef", PKI_EME_OAEP) Debug.Print "RSA_Encrypt() returns " & nEncLen & " (expecting 128 = 1024 bits)" ' Allocate memory for byte array ReDim abEnc(nEncLen - 1) ' Do the business - this should always give the same result nEncLen = RSA_Encrypt(abEnc(0), nEncLen, abMsg(0), nMsgLen, strPubKeyFile, "seed=18b776ea21069d69776a33e96bad48e1dda0a5ef", PKI_EME_OAEP) Debug.Print "ENC=" & cnvHexStrFromBytes(abEnc) ' Known answer from test vector strOkHex = "354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad468fb21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618c21a535fa9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e657a05a266426d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5210035d47ac72e8a" Debug.Print "OK =" & strOkHex ' 2. Decrypt - the private key is unencrypted with no password nDecLen = RSA_Decrypt(0, 0, abEnc(0), nEncLen, strPriKeyFile, "", "", PKI_EME_OAEP) Debug.Print "RSA_Decrypt() returns " & nDecLen ' Allocate memory for byte array ReDim abDec(nDecLen - 1) ' Decrypt nDecLen = RSA_Decrypt(abDec(0), nDecLen, abEnc(0), nEncLen, strPriKeyFile, "", "", PKI_EME_OAEP) Debug.Print "DEC=" & cnvHexStrFromBytes(abDec) ' 3. Encrypt using RSA-OAEP using SHA-256 nEncLen = RSA_Encrypt(0, 0, abMsg(0), nMsgLen, strPubKeyFile, "", PKI_EME_OAEP + PKI_HASH_SHA256) Debug.Print "RSA_Encrypt() returns " & nEncLen & " (expecting 128 = 1024 bits)" ' Allocate memory for byte array ReDim abEnc(nEncLen - 1) ' Do the business - this will be different each time nEncLen = RSA_Encrypt(abEnc(0), nEncLen, abMsg(0), nMsgLen, strPubKeyFile, "", PKI_EME_OAEP + PKI_HASH_SHA256) Debug.Print "ENC=" & cnvHexStrFromBytes(abEnc) ' 4. Decrypt - we must specify the hash function used to encrypt nDecLen = RSA_Decrypt(0, 0, abEnc(0), nEncLen, strPriKeyFile, "", "", PKI_EME_OAEP + PKI_HASH_SHA256) Debug.Print "RSA_Decrypt() returns " & nDecLen ' Allocate memory for byte array ReDim abDec(nDecLen - 1) ' Decrypt nDecLen = RSA_Decrypt(abDec(0), nDecLen, abEnc(0), nEncLen, strPriKeyFile, "", "", PKI_EME_OAEP + PKI_HASH_SHA256) Debug.Print "DEC=" & cnvHexStrFromBytes(abDec)
MSG=6628194E12073DB03BA94CDA9EF9532397D50DBA79B987004AFEFE34 RSA_Encrypt() returns 128 (expecting 128 = 1024 bits) ENC=354FE67B4A126D5D35FE36C777791A3F7BA13DEF484E2D3908AFF722FAD468FB21696DE95D0BE911C2D3174F8AFCC201035F7B6D8E69402DE5451618C21A535FA9D7BFC5B8DD9FC243F8CF927DB31322D6E881EAA91A996170E657A05A266426D98C88003F8477C1227094A0D9FA1E8C4024309CE1ECCCB5210035D47AC72E8A OK =354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad468fb21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618c21a535fa9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e657a05a266426d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5210035d47ac72e8a RSA_Decrypt() returns 28 DEC=6628194E12073DB03BA94CDA9EF9532397D50DBA79B987004AFEFE34 RSA_Encrypt() returns 128 (expecting 128 = 1024 bits) ENC=9BF3C801D9C73CD6FDDBF3C80715DD83A076D11BDCC1F73DC3ED7999EB2A4BB18296591E0B574374BC17CFF2EC290BD4730D70C9E1AEFA1D453F64A1C15A4C8ECA4E6CE9E1EF76B9253B6636426A8BC16B65A76BD280AB8DD5DF7607F5EF09D2BCC72CABD2E26608DD17FF80705861A79E11F50DDEA6083A567B4EEA40CAA2C5 RSA_Decrypt() returns 28 DEC=6628194E12073DB03BA94CDA9EF9532397D50DBA79B987004AFEFE34
Dim strPubKeyFile As String Dim lpMsg() As Byte Dim lpEnc() As Byte Dim strPriKeyFile As String Dim lpDec() As Byte ' Message to be encrypted: lpMsg = cnvBytesFromHexStr("6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34") Debug.Print "MSG=" & cnvHexStrFromBytes(lpMsg) ' Use RSA-OEAP with SHA-256 strPubKeyFile = "rsa-oaep-1.pub" lpEnc = rsaEncrypt(lpMsg, strPubKeyFile, PKI_EME_OAEP + PKI_HASH_SHA256) ' NB different each time... Debug.Print "ENC=" & cnvHexStrFromBytes(lpEnc) strPriKeyFile = "rsa-oaep-1.p8" lpDec = rsaDecrypt(lpEnc, strPriKeyFile, "", PKI_EME_OAEP + PKI_HASH_SHA256) Debug.Print "DEC=" & cnvHexStrFromBytes(lpDec) strPubKeyFile = "rsa-oaep-1.pub" ' Set seed to fixed value for debugging.... lpEnc = rsaEncrypt(lpMsg, strPubKeyFile, PKI_EME_OAEP, "seed=18b776ea21069d69776a33e96bad48e1dda0a5ef") Debug.Print "ENC=" & cnvHexStrFromBytes(lpEnc) Debug.Print "OK =354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad468fb" _ & "21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618c21a535f" _ & "a9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e657a05a266426" _ & "d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5210035d47ac72e8a" ' Decrypt strPriKeyFile = "rsa-oaep-1.p8" lpDec = rsaDecrypt(lpEnc, strPriKeyFile, "", PKI_EME_OAEP) Debug.Print "DEC=" & cnvHexStrFromBytes(lpDec)
RSA_Decrypt RSA_EncodeMsg RSA_RawPublic
Creates an RSA key string in internal format from an XML string.
Public Declare Function RSA_FromXMLString Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nOutChars As Long, ByVal strXmlString As String,
ByVal nOptions As Long) As Long
nRet = RSA_FromXMLString(strOutput, nOutChars,
strXmlString, nOptions) As Long
long __stdcall RSA_FromXMLString(char *szOutput, long nOutChars, const char *szXmlString, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function rsaFromXMLString (szXmlString As String, Optional nOptions As Long = 0) As String
Rsa.FromXMLString Method (String)
Rsa.FromXMLString Method (String, Rsa.XmlOptions)
Rsa.FromXMLString Method (String, Boolean)
static std::string dipki::Rsa::FromXMLString (const std::string &xmlstr, XmlOptions opts=XmlOptions::None)
static Rsa.from_xmlstring(xmlstr, opts=0)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
A key string created with this function can be used in the other RSA functions in this toolkit
that require a key in "internal" format.
Use this function to import an RSA key from another application.
Only US-ASCII characters are supported.
The XML data should be well formed and must contain either an
RSAKeyValue or RSAKeyPair element according to
[XMLDSIG] or [XKMS2].
The parser has been designed to be pretty forgiving but don't push it too far.
The first such valid element found in the string will be converted and other data will be ignored.
If the XML data only contains the public key elements, the resulting internal string will contain a public key
and can be used in the functions in this toolkit that require a public key string.
If the XML data contains all the private key elements, the internal string will contain a private key
unless the PKI_XML_EXCLPRIVATE option is used.
To convert a private key, all components of the key pair must be present; namely,
the <Modulus>, <Exponent>,
<D>, <P>, <Q>, <DP>, <DQ>,
and <InverseQ> elements as specified in [XKMS2].
To allow compatibility with older versions of XKMS out there,
the deprecated elements <QINV>, <PublicExponent>
and <PrivateExponent> will be accepted.
[New in v20.0]
Element names with a prefix, e.g. <ds:Modulus>, are now accepted.
To make life easier to import RSA key data that exists in hexadecimal format, the user can
force the function to decode the data in hexadecimal format instead of base64 by adding an attribute
with the value "hexBinary" to each of the component elements of the RSAKeyValue. For example
<Exponent EncodingType="hexBinary">010001</Exponent>
The attribute name is not important. This practice is not in conformance with any existing W3C standard (that we're aware of, anyway) but is included for convenience where the user is creating the XML file by hand using hex data.
This example converts an XML string into an internal public key that can be used in the other public key functions in this toolkit.
Dim strInternalKey As String
Dim strXML As String
Dim nLen As Long
Dim nRet As Long
strXML = "<RSAKeyValue>" _
& "<Modulus>CmZ5HcaYgWjeerd0Gbt/sMABxicQJwB1FClC4ZqNjFH" _
& "QU7PjeCod5dxa9OvplGgXARSh3+Z83Jqa9V1lViC7qw==</Modulus>" _
& "<Exponent>AQAB</Exponent>" _
& "</RSAKeyValue>"
nLen = RSA_FromXMLString("", 0, strXML, 0)
If nLen <= 0 Then
MsgBox ("Error: " & nLen)
Exit Function
End If
strInternalKey = String(nLen, " ")
nLen = RSA_FromXMLString(strInternalKey, Len(strInternalKey), strXML, 0)
strInternalKey = Left(strInternalKey, nLen)
Debug.Print "INTKEY=" & strInternalKey
nRet = RSA_CheckKey(strInternalKey, 0)
Debug.Print "RSA_CheckKey returns " & nRet
The second example is the same as the first except the XML data is in hexadecimal format.
Dim strInternalKey As String
Dim strXML As String
Dim nLen As Long
Dim nRet As Long
strXML = "<RSAKeyValue>" _
& "<Modulus EncodingType='hexBinary'>0A66791D" _
& "C6988168DE7AB77419BB7FB0C001C627102700751429" _
& "42E19A8D8C51D053B3E3782A1DE5DC5AF4EBE9946817" _
& "0114A1DFE67CDC9A9AF55D655620BBAB</Modulus>" _
& "<Exponent EncodingType='hexBinary'>010001</Exponent>" _
& "</RSAKeyValue>"
nLen = RSA_FromXMLString("", 0, strXML, 0)
If nLen <= 0 Then
MsgBox ("Error: " & nLen)
Exit Function
End If
strInternalKey = String(nLen, " ")
nLen = RSA_FromXMLString(strInternalKey, Len(strInternalKey), strXML, 0)
strInternalKey = Left(strInternalKey, nLen)
Debug.Print "INTKEY=" & strInternalKey
nRet = RSA_CheckKey(strInternalKey, 0)
Debug.Print "RSA_CheckKey returns " & nRet
Both examples should produce the output (shortened here):
INTKEY=MEcCQApmeR3...yamvVdZVYgu6sCAwEAAQ== RSA_CheckKey returns 1
Dim strPrivateKey As String
strPrivateKey = rsaReadPrivateKey("AlicePrivRSASign.p8e", "password")
Debug.Print rsaToXMLString(strPrivateKey, 0)
Debug.Print rsaToXMLString(strPrivateKey, PKI_XML_EXCLPRIVATE Or PKI_XML_HEXBINARY)
Debug.Print rsaToXMLStringEx(strPrivateKey, "ds", PKI_XML_EXCLPRIVATE)
' Now derive internal private key string from XML
Dim strXML As String
Dim strKey As String
strXML = rsaToXMLString(strPrivateKey)
strKey = rsaFromXMLString(strXML)
Debug.Print "Key length = " & RSA_KeyBits(strKey) & " bits"
Extracts an encrypted private key from a PKCS-12 PKCS8ShroudedKeyBag, saving the output directly as a new file.
Public Declare Function RSA_GetPrivateKeyFromPFX Lib "diCrPKI.dll"
(ByVal strOutputFile As String, ByVal strPfxFile As String,
ByVal nOptions As Long) As Long
nRet = RSA_GetPrivateKeyFromPFX(strOutputFile, strPfxFile,
nOptions) As Long
long __stdcall RSA_GetPrivateKeyFromPFX(const char *szFileOut, const char *szPfxFile, long nOptions);
If successful, it returns the number of bytes written to the output file; otherwise it returns a negative error code.
Rsa.GetPrivateKeyFromPFX Method
static int dipki::Rsa::GetPrivateKeyFromPFX (const std::string &outputFile, const std::string &pfxFile)
static Rsa.get_privatekey_from_pfx(outputfile, pfxfile)
The first pkcs-12-pkcs-8ShroudedKeyBag found in the PFX file will be extracted and saved directly
as a BER-encoded EncryptedPrivateKeyInfo file.
No decryption or other conversion is carried out.
nChars = RSA_GetPrivateKeyFromPFX(strEPKFile, strPfxFile, 0)
RSA_ReadEncPrivateKey RSA_ReadPrivateKeyFromPFX PFX_MakeFile
Reads a public key from an X.509 certificate into an "internal" public key string.
Public Declare Function RSA_GetPublicKeyFromCert Lib "diCrPKI.dll"
(ByVal strPublicKey As String, ByVal nOutChars As Long, ByVal strCertFileName As String,
ByVal nOptions As Long) As Long
nRet = RSA_GetPublicKeyFromCert(strPublicKey, nOutChars,
strCertFileName, nOptions) As Long
long __stdcall RSA_GetPublicKeyFromCert(char *szOutput, long nOutChars, const char *szCertFile, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Rsa.GetPublicKeyFromCert Method
Call the function with an empty or NULL szOutput string or zero nOutChars parameter to find out the required length of the output string. C/C++ users should add one to this value when allocating memory. Both binary BER-encoded and PEM-style base64-encoded certificates can be read, or the certificate can be passed directly as a string in base64 representation.
Woops! The name of this function is an exception to our usual convention that "Read" means read-into-internal-string and "Get" means extract-and-save-as-a-file. By rights this function should be called "RSA_ReadPublicKeyFromCert". Sorry.
This code reads Alice's public key from her certificate and saves in a PKCS#1 public key file. The certificate is from [SMIME-EX].
Dim strCertFile As String Dim strKeyFile As String Dim strPublicKey As String Dim nChars As Long Dim nRet As Long strCertFile = "AliceRSASignByCarl.cer" ' First find out the length of string we need nChars = RSA_GetPublicKeyFromCert(vbNullString, 0, strCertFile, 0) Debug.Print "RSA_GetPublicKeyFromCert returns " & nChars & " (expecting +ve)" If nChars <= 0 Then Debug.Print "ERROR: " & pkiErrorLookup(nChars) Exit Sub End If ' Pre-dimension the string to receive data - IMPORTANT strPublicKey = String(nChars, " ") ' Read in the Public Key in our "internal" format nRet = RSA_GetPublicKeyFromCert(strPublicKey, nChars, strCertFile, 0) Debug.Print "Public key is " & RSA_KeyBits(strPublicKey) & " bits long" ' Now save as a PKCS#1 public key file strKeyFile = "AlicePubRSA.pub" nRet = RSA_SavePublicKey(strKeyFile, strPublicKey, 0) Debug.Print "RSA_SavePublicKey returns " & nRet If nRet = 0 Then Debug.Print "Saved as public key file '" & strKeyFile & "'" Else Debug.Print "ERROR: " & pkiErrorLookup(nRet) End If
This should result in the output:
RSA_GetPublicKeyFromCert returns 220 (expecting +ve) Public key is 1024 bits long RSA_SavePublicKey returns 0 Saved as public key file 'AlicePubRSA.pub'
RSA_SavePublicKey RSA_PublicKeyFromPrivate X509_GetCertFromP7Chain X509_GetCertFromPFX
Returns the length of key in bits given the public or private key string.
Public Declare Function RSA_KeyBits Lib "diCrPKI.dll"
(ByVal strKey As String) As Long
nRet = RSA_KeyBits(strKey)
long __stdcall RSA_KeyBits(const char *szKeyString);
returns the number of significant bits in the key modulus or a negative error code.
Public Function rsaKeyBits (szKeyString As String) As Long
Rsa.KeyBits Method (String)
Rsa.KeyBits Method (StringBuilder)
static int dipki::Rsa::KeyBits (const std::string &keyStr)
static Rsa.key_bits(keystr)
Returns the length of key in complete bytes (octets) given the public or private key string.
Public Declare Function RSA_KeyBytes Lib "diCrPKI.dll"
(ByVal strKey As String) As Long
nRet = RSA_KeyBytes(strKey)
long __stdcall RSA_KeyBytes(const char *szKeyString);
returns the number of complete bytes (8-bit octets) in the key modulus or a negative error code.
Public Function rsaKeyBytes (szKeyString As String) As Long
Rsa.KeyBytes Method (String)
Rsa.KeyBytes Method (StringBuilder)
static int dipki::Rsa::KeyBytes (const std::string &keyStr)
static Rsa.key_bytes(keystr)
Use this function to find out the required length of the encryption block for "raw" RSA encryption.
RSA_KeyBits RSA_RawPublic RSA_RawPrivate
Computes the hash code of an "internal" RSA public or private key string.
Public Declare Function RSA_KeyHashCode Lib "diCrPKI.dll"
(ByVal strKey As String) As Long
nRet = RSA_KeyHashCode(strKey)
long __stdcall RSA_KeyHashCode(const char *szKeyString);
A 32-bit hash code for the key, or zero on error.
Rsa.KeyHashCode Method (String)
Rsa.KeyHashCode Method (StringBuilder)
static uint32_t dipki::Rsa::KeyHashCode (const std::string &intKeyString)
static Rsa.key_hashcode(keystr)
Use this function to compare internal key strings. As of version 3.0, internal key strings are encrypted
and cannot be compared directly.
The actual string values may or may not be the same even though the underlying key is.
The hash code value will be the same for a given key.
The hash code is computed to an internal algorithm and may return any integer value
between -2,147,483,648 and 2,147,483,647.
If the key string is invalid, the return value is zero and a nonzero error code will be set (use PKI_ErrorCode to check).
There is a very small chance (one in 4 billion) that a valid key string returns a hash code of zero.
See the example in RSA_ReadPrivateKeyInfo.
Verifies that a pair of "internal" RSA private and public key strings are matched.
Public Declare Function RSA_KeyMatch Lib "diCrPKI.dll"
(ByVal strPrivateKey As String, ByVal strPublicKey As String) As Long
nRet = RSA_KeyMatch(strPrivateKey, strPublicKey)
long __stdcall RSA_KeyMatch(const char *szPrivateKey, const char *szPublicKey);
If the pair of private and public keys match, the return value is zero (0); if the key strings are valid but not matched, the return value is NO_MATCH_ERROR (-21). If an error occurs, it returns a nonzero error code.
Rsa.KeyMatch Method (String)
Rsa.KeyMatch Method (StringBuilder)
static bool dipki::Rsa::KeyMatch (const std::string &priKeyStr, const std::string &pubKeyStr)
static Rsa.key_match(prikeystr, pubkeystr)
This function allows you to check that a private key file is matched with the public key in an X.509 certificate. You must read the keys into "internal" key strings before comparing. Note that the return value for success is zero.
Dim strCertFile As String Dim strKeyFile As String Dim strPassword As String Dim strPublicKey As String Dim strPrivateKey As String Dim nRet As Long ' Input files strCertFile = "AAA010101AAAsd.cer" strKeyFile = "AAA010101AAA_0408021316S.key" ' Test password - CAUTION: DO NOT hardcode production passwords! strPassword = "Empresa1" ' Read in private key from encrypted .key file strPrivateKey = rsaReadPrivateKey(strKeyFile, strPassword) If Len(strPrivateKey) > 0 Then Debug.Print "Private key is " & RSA_KeyBits(strPrivateKey) & " bits" Else Debug.Print "ERROR: Cannot read private key file." Exit Sub End If ' Clean up password as we are done with it strPassword = wipeString(strPassword) ' Read in public key from certificate strPublicKey = rsaGetPublicKeyFromCert(strCertFile) If Len(strPublicKey) > 0 Then Debug.Print "Public key is " & RSA_KeyBits(strPublicKey) & " bits" Else Debug.Print "ERROR: Cannot read certificate file." Exit Sub End If ' See if the two key strings match nRet = RSA_KeyMatch(strPrivateKey, strPublicKey) If nRet = 0 Then Debug.Print "OK, key strings match." Else Debug.Print "FAILED: key strings do not match." End If ' Clean up private key string strPrivateKey = wipeString(strPrivateKey)
Using the sample Mexican Government SAT files, the output is as follows:
Private key is 1024 bits Public key is 1024 bits OK, key strings match.
Extracts a base64-encoded RSA key value from internal key string.
Public Declare Function RSA_KeyValue Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strKeyString As String, ByVal strFieldName As String, ByVal nOptions As Long) As Long
nRet = RSA_KeyValue(strOutput, nOutChars, strKeyString, strFieldName, nOptions)
long __stdcall RSA_KeyValue(char *szOutput, long nOutChars, const char *szKeyString, const char *szFieldName, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function rsaKeyValue (szKeyString As String, szFieldName As String, Optional nOptions As Long = 0) As String
static std::string dipki::Rsa::KeyValue (const std::string &keyStr, const std::string &fieldName)
static Rsa.key_value(keystr, fieldname)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The output is a continuous string of base64 characters
suitable for a <RSAKeyValue> node in an XML-DSIG document.
A typical <RSAKeyValue> node looks like this:
<RSAKeyValue>
<Modulus>
4IlzOY3Y9fXoh3Y5f06wBbtTg94Pt6vcfcd1KQ0FLm0S36aGJtTSb6pYKfyX7PqCUQ8wgL6xUJ5GRPEsu9gyz8
ZobwfZsGCsvu40CWoT9fcFBZPfXro1Vtlh/xl/yYHm+Gzqh0Bw76xtLHSfLfpVOrmZdwKmSFKMTvNXOFd0V18=
</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
Use this function to populate the fields <Modulus> and <Exponent> for a given RSA key,
or to use the values in other computations.
Dim nChars As Long Dim strKeyString As String Dim strFieldName As String Dim strValue As String ' Read in key to internal string strKeyString = rsaReadPublicKey("AliceRSASignByCarl.cer") strFieldName = "Modulus" nChars = RSA_KeyValue("", 0, strKeyString, strFieldName, 0) If (nChars < 0) Then Debug.Print "ERROR: " & pkiErrorLookup(nChars) Exit Sub End If ' Dimension output strValue = String(nChars, " ") nChars = RSA_KeyValue(strValue, nChars, strKeyString, strFieldName, 0) Debug.Print strFieldName & "=" & strValue strFieldName = "Exponent" nChars = RSA_KeyValue("", 0, strKeyString, strFieldName, 0) If (nChars < 0) Then Debug.Print "ERROR: " & pkiErrorLookup(nChars) Exit Sub End If ' Dimension output strValue = String(nChars, " ") nChars = RSA_KeyValue(strValue, nChars, strKeyString, strFieldName, 0) Debug.Print strFieldName & "=" & strValue
Modulus=4IlzOY3Y9fXoh3Y5f06wBbt ... +Gzqh0Bw76xtLHSfLfpVOrmZdwKmSFKMTvNXOFd0V18= Exponent=AQAB
Dim strKeyString As String
Dim strFieldName As String
Dim strValue As String
strKeyString = rsaReadPublicKey("AliceRSASignByCarl.cer")
strFieldName = "Modulus"
strValue = rsaKeyValue(strKeyString, strFieldName)
Debug.Print strFieldName & "=" & strValue
strFieldName = "Exponent"
strValue = rsaKeyValue(strKeyString, strFieldName)
Debug.Print strFieldName & "=" & strValue
Generate an RSA key pair and save as two key files.
[Superseded by RSA_MakeKeysXtd.]
Public Declare Function RSA_MakeKeys Lib "diCrPKI.dll"
(ByVal strPubKeyFile As String, ByVal strPvkKeyFile As String,
ByVal nBits As Long, ByVal nExpFermat As Long, ByVal nTests As Long,
ByVal nCount As Long,
ByVal strPassword As String,
ByVal strSeed As String, ByVal nSeedLen As Long,
ByVal nOptionFlags As Long) As Long
nRet = RSA_MakeKeys(strPublicKeyFile, strPrivateKeyFile, nBits, nExpFermat,
nTests, nCount, strPassword,
strSeed, nSeedLen, nOptionFlags)
long __stdcall RSA_MakeKeys(const char *szPubKeyFile, const char *szEpkFile, long nBits, long nExpFermat, long nTests, long nCount, const char *szPassword, const void *lpSeed, long nSeedLen, long nOptions);
"pbeWithSHAAnd3-KeyTripleDES-CBC" (default)"pkcs5PBES2" plus one ofdes-EDE3-CBC (default)AES128-CBCAES192-CBCAES256-CBCIf successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function rsaMakeKeys (szPubKeyFile As String, szPriKeyFile As String, szPassword As String, nBits As Long, Optional nExpFermat As Long = PKI_RSAEXP_EQ_65537, Optional szParams As String = "", Optional nOptions As Long = 0) As Long
Rsa.MakeKeys Method (String, String, Int32, Rsa.PublicExponent, Int32, String, Rsa.PbeOptions, Boolean, Byte[])
Rsa.MakeKeys Method (String, String, Int32, Rsa.PublicExponent, Int32, String, CipherAlgorithm, HashAlgorithm, Rsa.Format, Boolean)
static int dipki::Rsa::MakeKeys (const std::string &publicKeyFile, const std::string &privateKeyFile, const std::string &password, int nbits, PublicExponent exponent=PublicExponent::Exp_EQ_65537, PbeScheme pbes=PbeScheme::Default, const std::string ¶mString="", Format fileFormat=Format::Binary, bool showProgress=false)
The RSA key is stored by default as a pair of DER-encoded binary files.
The public and private keys are encoded into ASN.1 values of type
RSAPublicKey and RSAPrivateKey respectively (defined in PKCS #1).
The private key is then encrypted and encoded into a PKCS #8 EncryptedPrivateKeyInfo type.
Any existing files of the same names will be overwritten without warning.
The key length must be greater than 96 bits. The value of the exponent is limited to the five values listed.
The password and iteration count are used to encrypt the private key according to the
specified PBE algorithm specified in nOptionFlags.
The password should be a string of ASCII characters and must not contain any NUL characters (i.e. Chr(0)).
The seed is optional and is used to supplement the seeding of the random number generator.
The user may use the seed to provide some additional value ("user-supplied entropy") that is unique when the
keys are being generated.
See Random Number Generator and Seeds for more information.
The default format for the files is binary DER-encoded format.
Use either the PKI_KEY_FORMAT_PEM or the PKI_KEY_FORMAT_SSL flag to save in
base64 "PEM" format. Files saved with the PKI_KEY_FORMAT_SSL flag should be compatible
with OpenSSL. For more details on the formats, see
RSA_SavePublicKey()
and RSA_SaveEncPrivateKey().
Generating RSA key pairs can take some time. On a 1GHz P3 test machine, the following times were typical:
| Key size | Time |
|---|---|
| 512 | < 1 second |
| 1024 | 5 seconds |
| 2048 | 1 minute |
| 4096 | 6 minutes |
| 8192 | 1 hour |
Some programs like Office Access will get bored waiting for the longer processes to finish and may hang.
Setting the PKI_KEYGEN_INDICATE flag will show progress in a separate console window (actually two, one for
p and one for q). Having a console window show progress will keep the parent application happy.
A dot "." indicates a new candidate is being tested,
and an asterisk "*" indicates that a Rabin-Miller test has been carried
out (that is the expensive part of the process). The program will close these console windows down automatically.
Do not use the PKI_KEYGEN_INDICATE option in a multi-threaded environment.
For console-based programs, this option just shows the progress in the standard output.
Caution: pressing Ctrl-C or Ctrl-Break in the console window will kill your entire process altogether; that is, abort your whole application, which may not be what you want.
There is a very, very small possibility that the generator may fail to find a suitable prime number candidate
within the number of iterations it carries out. If this happens (we've never seen it, but it could in theory), the function
will return a KEYGEN_FAILED_ERROR error code 24. This in itself does not indicate a
systemic problem with the Toolkit, just an incredibly unlucky event. Let us know if it happens more than once.
Dim nRet As Long Dim sPublicKeyFile As String Dim sPrivateKeyFile As String Dim sPassword As String sPublicKeyFile = "mykey.pub" sPrivateKeyFile = "mykey.p8e" sPassword = "password" ' Create a new pair of RSA keys saved as BER-encoded files Debug.Print "About to create a new RSA key pair..." nRet = RSA_MakeKeys(sPublicKeyFile, sPrivateKeyFile, 512, _ PKI_RSAEXP_EQ_3, 50, 1000, sPassword, "", 0, 0) Debug.Print "RSA_MakeKeys returns " & nRet & " (expected 0)"
The example above will generate a 512-bit RSA key pair and store in two files, a public key file mykey.pub
and an encrypted private key file mykey.p8e. The exponent will be 3.
Rabin-Miller tests will be carried out 50 times to verify that the values of p and q are prime.
The private key will be encrypted using the default "pbeWithSHAAnd3-KeyTripleDES-CBC" algorithm using the password
"password" and an iteration count of 1000.
strSeed = "yyyseed345"
nRet = RSA_MakeKeys(sPublicKeyFile, sPrivateKeyFile, 2048,
PKI_RSAEXP_EQ_65537, 64, 3000, "94tMhvTr7gvVy48q", strSeed, Len(strSeed),
PKI_PBE_PBKDF2_AES128)
The second example generates a 2048-bit RSA key pair with the exponent 65537 (0x10001). Sixty-four Rabin-Miller tests are used to test for primality. The private key will be encrypted using the PBES2 algorithm with AES-128 as the encryption scheme, the password "94tMhvTr7gvVy48q", and an iteration count of 3000. The string "yyyseed345" will be added to the RNG seeding process. Note the use of PKI_PBE_PBKDF2_AES128 as a replacement for the older (but still valid) option PKI_PBE_PBES2+PKI_BC_AES128.
RSA_ReadEncPrivateKey RSA_ReadPublicKey RSA_SaveEncPrivateKey RSA_SavePublicKey
Generate an RSA key pair and save as two key files.
Public Declare Function RSA_MakeKeysXtd Lib "diCrPKI.dll" (ByVal strPubKeyFile As String, ByVal strPriKeyFile As String, ByVal strPassword As String, ByVal nBits As Long, ByVal nExpFermat As Long, ByVal strParams As String, ByVal nOptions As Long) As Long
nRet = RSA_MakeKeysXtd(strPubKeyFile, strPriKeyFile, strPassword, nBits, nExpFermat, strParams, nOptionFlags)
long __stdcall RSA_MakeKeysXtd(const char *szPubKeyFile, const char *szPriKeyFile, const char *szPassword, long nBits, long nExpFermat, const char *szParams, long nOptions);
"" for defaults.
Otherwise include a set of attribute-value pairs separated by a semi-colon ";" to set options from the following
count=<nnn> to set the iteration count in the encrypted private key used in the PBKDF method,
e.g. "count=5000;" [default=2048]
prf=<hmac-name> to change the HMAC algorithm used in the PBKDF2 method,
e.g. "prf=hmacWithSHA256;" [default=hmacwithSHA1]
rngseed=<string> to add some extra user-specified additional seed for the random number generator,
e.g. "rngseed=pqrrr1234xyz;"
{hmacWithSHA1|hmacWithSHA224|hmacWithSHA256|hmacWithSHA384|hmacWithSHA512}.
"pbeWithSHAAnd3-KeyTripleDES-CBC" from PKCS12 (default)des-EDE3-CBCaes128-CBCaes192-CBCaes256-CBCIf successful, the return value is zero; otherwise it returns a nonzero error code.
static Rsa.make_keys(pubkeyfile, prikeyfile, nbits, exponent, password, pbes=0, params='', fileformat=0)
The RSA keys are stored by default as a pair of DER-encoded binary files.
Setting the PKI_KEYGEN_INDICATE flag will show progress in a separate console window (actually two, one for p and one for q). Having a console window show progress will keep a parent application (like MS Access) happy and prevent it hanging due to boredom. The program will close these console windows down automatically (do not use Ctrl-C or Ctrl-Break: it will kill your entire process altogether!). Do not use the PKI_KEYGEN_INDICATE option in a multi-threaded environment. For console-based programs, this option just shows the progress in the standard output.
Dim r As Long
' Create a 2048-bit RSA key pair using defaults
r = rsaMakeKeys("myrsa2048.pub", "myrsa2048.p8e", "password", 2048)
' Same but using stronger security and in PEM format
r = rsaMakeKeys("myrsa2048ex.pub", "myrsa2048ex.p8e", "password1", 2048,,"count=6000;prf=hmacWithSHA256", PKI_PBE_PBKDF2_AES128 Or PKI_KEY_FORMAT_PEM)
Converts an internal RSA private key string into an internal public key string.
Public Declare Function RSA_PublicKeyFromPrivate Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strKeyString As String, ByVal nOptions As Long) As Long
nRet = RSA_PublicKeyFromPrivate(strOutput, nOutChars,
strKeyString, nOptions) As Long
long __stdcall RSA_PublicKeyFromPrivate(char *szOutput, long nOutChars, const char *szKeyString, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function rsaPublicKeyFromPrivate (szKeyString As String, Optional nOptions As Long = 0) As String
Rsa.PublicKeyFromPrivate Method
static std::string dipki::Rsa::PublicKeyFromPrivate (const std::string &keyStr)
static Rsa.publickey_from_private(intkeystr)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
Use this function if you need a public key string but only have the corresponding private key file. The format used to store RSA private keys contains both the public and private components (that is, n and e are present in both) so we can obtain the public key from its corresponding private key. Note that internal key strings are only valid for the current session.
This example reads in a private key to an internal private key string, displays some information about the key, then converts it to a public key string and displays its properties.
Dim strPriKeyFile As String Dim strPrivateKey As String Dim strPublicKey As String Dim nChars As Long Dim nCode As Long Dim nRet As Long ' Read private key from encrypted private key file into internal string form strPriKeyFile = "BobPrivRSAEncrypt.p8e" strPrivateKey = rsaReadPrivateKey(strPriKeyFile, "password") If Len(strPrivateKey) = 0 Then Exit Sub 'Catch error here ' Display some info about it Debug.Print "Private key length = " & RSA_KeyBits(strPrivateKey) & " bits" nCode = RSA_KeyHashCode(strPrivateKey) Debug.Print "KeyHashCode=" & Hex(nCode) nRet = RSA_CheckKey(strPrivateKey, 0) Debug.Print "RSA_CheckKey returns " & nRet & ": (PKI_VALID_PRIVATEKEY=" & PKI_VALID_PRIVATEKEY & ")" ' Convert to public key string nChars = RSA_PublicKeyFromPrivate("", 0, strPrivateKey, 0) If nChars <= 0 Then Exit Sub ' Catch error here strPublicKey = String(nChars, " ") nChars = RSA_PublicKeyFromPrivate(strPublicKey, Len(strPublicKey), strPrivateKey, 0) ' Display some info about it Debug.Print "Public key length = " & RSA_KeyBits(strPublicKey) & " bits" nCode = RSA_KeyHashCode(strPublicKey) Debug.Print "KeyHashCode=" & Hex(nCode) nRet = RSA_CheckKey(strPublicKey, 0) Debug.Print "RSA_CheckKey returns " & nRet & ": (PKI_VALID_PUBLICKEY=" & PKI_VALID_PUBLICKEY & ")" ' Clean up strPrivateKey = wipeString(strPrivateKey)
Note that the KeyHashCodes and bit lengths are the same.
Private key length = 1024 bits KeyHashCode=6BCC120C RSA_CheckKey returns 0: (PKI_VALID_PRIVATEKEY=0) Public key length = 1024 bits KeyHashCode=6BCC120C RSA_CheckKey returns 1: (PKI_VALID_PUBLICKEY=1)
Dim strPrivateKey As String Dim strPublicKey As String ' Read in private key to internal string strPrivateKey = rsaReadPrivateKey("BobPrivRSAEncrypt.p8e", "password") Debug.Assert Len(strPrivateKey) > 0 Debug.Print "Private key length = " & RSA_KeyBits(strPrivateKey) & " bits" Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strPrivateKey)) ' Convert to public key string strPublicKey = rsaPublicKeyFromPrivate(strPrivateKey) Debug.Print "Public key length = " & RSA_KeyBits(strPublicKey) & " bits" Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strPublicKey))
RSA_SavePublicKey RSA_ReadEncPrivateKey
Transforms (that is, encrypts or decrypts) raw data using an RSA private key.
Public Declare Function RSA_RawPrivate Lib "diCrPKI.dll"
(ByRef lpData As Byte, ByVal nDataLen As Long,
ByVal strPrivateKey As String, ByVal nOptions As Long) As Long
nRet = RSA_RawPrivate(lpData(0), nDataLen, strPrivateKey, nOptions)
long __stdcall RSA_RawPrivate(unsigned char *lpData, long nDataLen, const char *szPrivateKey, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function rsaRawPrivate (lpData() As Byte, szPrivateKey As String, Optional nOptions As Long = 0) As Byte()
Rsa.RawPrivate Method (Byte[], String)
Rsa.RawPrivate Method (Byte[], String, Int32)
static bvec_t dipki::Rsa::RawPrivate (const bvec_t &data, const std::string &keyStr)
static Rsa.raw_private(block, prikeystr)
The data must be the same length as the RSA key modulus (use RSA_KeyBytes() to find out this).
The output is written over the input. The RSA private key must be provided in the internal key string format.
This is adapted from "Some Examples of the PKCS Standards: An RSA Laboratories Technical Note",
Burton S. Kaliski Jr., 1993 [PKCS-EX].
It carries out the signing of the encryption block from section 3.2 using the 508-bit private key and then
verifies the signature using the corresponding public key.
The keys are stored in files rsa508.pub and rsa508.p8e.
Dim strEPKFile As String Dim strPubFile As String Dim strPassword As String Dim strPublicKey As String Dim strPrivateKey As String Dim nRet As Long Dim strOutputFile As String Dim abData() As Byte Dim nDataLen As Long Dim sHexData As String strEPKFile = "rsa508.p8e" strPassword = "password" ' Read in the deciphered private key string strPrivateKey = rsaReadPrivateKey(strEPKFile, strPassword) If Len(strPrivateKey) = 0 Then MsgBox "Unable to retrieve private key" Exit Function End If Debug.Print strPrivateKey ' Create some raw data to be RSA'd ' Ref: 3.2 Signing the CertificationRequestInfo encoding ' 64-octet EB in full: '00 01 ff ff ff ff ff ff ff ff ff ff ff ff ff ff 'ff ff ff ff ff ff ff ff ff ff ff ff ff 00 30 20 '30 0c 06 08 2a 86 48 86 f7 0d 02 02 05 00 04 10 'dc a9 ec f1 c1 5c 1b d2 66 af f9 c8 79 93 65 cd sHexData = "0001ffffffffffffffffffffffffffff" & _ "ffffffffffffffffffffffffff003020" & _ "300c06082a864886f70d020205000410" & _ "dca9ecf1c15c1bd266aff9c8799365cd" abData = cnvBytesFromHexStr(sHexData) nDataLen = UBound(abData) - LBound(abData) + 1 Debug.Print "Input: " & cnvHexStrFromBytes(abData) ' Now we have our data in a byte array and ' our private key in string format, ' we are ready to do a "raw" operation nRet = RSA_RawPrivate(abData(0), nDataLen, strPrivateKey, 0) Debug.Print "RSA_RawPrivate returns " & nRet If nRet <> 0 Then Debug.Print pkiGetLastError() Else ' Display our results in hex format Debug.Print "Output: " & cnvHexStrFromBytes(abData) End If ' Get the corresponding Public Key, also in a file strPubFile = "rsa508.pub" strPublicKey = rsaReadPublicKey(strPubFile) Debug.Print strPublicKey ' Do a "raw" encryption with the public key nRet = RSA_RawPublic(abData(0), nDataLen, strPublicKey, 0) Debug.Print "RSA_RawPublic returns " & nRet If nRet <> 0 Then Debug.Print pkiGetLastError() Else ' Display our results in hex format Debug.Print "Decrypt:" & cnvHexStrFromBytes(abData) End If
Dim strPrivateKey As String
Dim pt() As Byte
Dim ct() As Byte
strPrivateKey = rsaReadPrivateKey("rsa508.p8e", "password")
Debug.Assert Len(strPrivateKey) > 0
pt = cnvBytesFromHexStr("0001ffffffffffffffffffffffffffff" & _
"ffffffffffffffffffffffffff003020" & _
"300c06082a864886f70d020205000410" & _
"dca9ecf1c15c1bd266aff9c8799365cd")
ct = rsaRawPrivate(pt, strPrivateKey)
Debug.Print "CT=" & cnvHexStrFromBytes(ct)
Dim strPublicKey As String
Dim dt() As Byte
strPublicKey = rsaReadPublicKey("Rsa508.pub")
Debug.Assert Len(strPublicKey) > 0
dt = rsaRawPublic(ct, strPublicKey)
Debug.Print "DT=" & cnvHexStrFromBytes(dt)
RSA_RawPublic RSA_EncodeMsg Raw RSA Techniques
Transforms (that is, encrypts or decrypts) raw data using an RSA public key.
Public Declare Function RSA_RawPublic Lib "diCrPKI.dll"
(ByRef lpData As Byte, ByVal nDataLen As Long,
ByVal strPublicKey As String, ByVal nOptions As Long) As Long
nRet = RSA_RawPublic(lpData(0), nDataLen, strPublicKey, nOptions)
long __stdcall RSA_RawPublic(unsigned char *lpData, long nDataLen, const char *szPublicKey, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function rsaRawPublic (lpData() As Byte, szPublicKey As String, Optional nOptions As Long = 0) As Byte()
Rsa.RawPublic Method (Byte[], String)
Rsa.RawPublic Method (Byte[], String, Int32)
static bvec_t dipki::Rsa::RawPublic (const bvec_t &data, const std::string &keyStr)
static Rsa.raw_public(block, pubkeystr)
The data must be the same length as the RSA key modulus (use RSA_KeyBytes() to find out this).
The output is written over the input. The RSA public key must be provided in the internal key string format.
This is from Example 4.2 of [SMIME-EX]:
Dim sEncDataHex As String
Dim abData() As Byte
Dim nDataLen As Long
Dim strCertFile As String
Dim nKeyLen As Long
Dim strPublicKey As String
Dim nRet As Long
' Cut and paste from DUMPASN1 output
sEncDataHex = "2F 23 82 D2 F3 09 5F B8 0C 58 EB 4E" & _
"9D BF 89 9A 81 E5 75 C4 91 3D D3 D0" & _
"D5 7B B6 D5 FE 94 A1 8A AC E3 C4 84" & _
"F5 CD 60 4E 27 95 F6 CF 00 86 76 75" & _
"3F 2B F0 E7 D4 02 67 A7 F5 C7 8D 16" & _
"04 A5 B3 B5 E7 D9 32 F0 24 EF E7 20" & _
"44 D5 9F 07 C5 53 24 FA CE 01 1D 0F" & _
"17 13 A7 2A 95 9D 2B E4 03 95 14 0B" & _
"E9 39 0D BA CE 6E 9C 9E 0C E8 98 E6" & _
"55 13 D4 68 6F D0 07 D7 A2 B1 62 4C" & _
"E3 8F AF FD E0 D5 5D C7"
' Convert to bytes
abData = cnvBytesFromHexStr(sEncDataHex)
' Check
Debug.Print cnvHexStrFromBytes(abData)
strCertFile = "AliceRSASignByCarl.cer"
' Read in PublicKey as base64 string - pre-dimension first
nKeyLen = RSA_GetPublicKeyFromCert("", 0, strCertFile, 0)
Debug.Print "KeyLen = " & nKeyLen
If nKeyLen <= 0 Then
Debug.Print pkiGetLastError()
MsgBox "Unable to retrieve private key"
Exit Function
End If
' Pre-dimension the string to receive data
strPublicKey = String(nKeyLen, " ")
' Read in the Key
nRet = RSA_GetPublicKeyFromCert(strPublicKey, nKeyLen, strCertFile, 0)
Debug.Print "PubKey= " & strPublicKey
' Verify using the public key
nDataLen = UBound(abData) + 1
Debug.Print "Input: " & cnvHexStrFromBytes(abData)
nRet = RSA_RawPublic(abData(0), nDataLen, strPublicKey, 0)
Debug.Print "Output: " & cnvHexStrFromBytes(abData)
Stripping the PKCS-1.5 header 0001FFFF...FF00 from the output, we should get
3021300906052B0E03021A05000414406AEC085279BA6E16022D9E0629C0229687DD48
which is a DigestInfo containing the 20-byte SHA-1 hash
406AEC085279BA6E16022D9E0629C0229687DD48
Dim strPrivateKey As String
Dim pt() As Byte
Dim ct() As Byte
strPrivateKey = rsaReadPrivateKey("rsa508.p8e", "password")
Debug.Assert Len(strPrivateKey) > 0
pt = cnvBytesFromHexStr("0001ffffffffffffffffffffffffffff" & _
"ffffffffffffffffffffffffff003020" & _
"300c06082a864886f70d020205000410" & _
"dca9ecf1c15c1bd266aff9c8799365cd")
ct = rsaRawPrivate(pt, strPrivateKey)
Debug.Print "CT=" & cnvHexStrFromBytes(ct)
Dim strPublicKey As String
Dim dt() As Byte
strPublicKey = rsaReadPublicKey("Rsa508.pub")
Debug.Assert Len(strPublicKey) > 0
dt = rsaRawPublic(ct, strPublicKey)
Debug.Print "DT=" & cnvHexStrFromBytes(dt)
RSA_RawPrivate RSA_EncodeMsg Raw RSA Techniques
Reads from a file or string containing a private key into an "internal" private key string.
Public Declare Function RSA_ReadAnyPrivateKey Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strKeyFileOrString As String, ByVal strPassword As String, ByVal nOptions As Long) As Long
nRet = RSA_ReadAnyPrivateKey(strOutput, nOutChars, strKeyFileOrString, strPassword, nOptions) As Long
long __stdcall RSA_ReadAnyPrivateKey(char *szOutput, long nOutChars, const char *szKeyFileOrString, const char *szPassword, long nOptions);
"" if not encrypted.If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function rsaReadAnyPrivateKey (szKeyFileOrString As String, Optional szPassword As String = "", Optional nOptions As Long = 0) As String
Public Function rsaReadPrivateKey (szKeyFileOrString As String, Optional szPassword As String = "", Optional nOptions As Long = 0) As String
static std::string dipki::Rsa::ReadPrivateKey (const std::string &keyFileOrString, const std::string &password="")
static Rsa.read_private_key(keyfileorstr, password="")
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
This function will attempt to read the private key from "any" supported format. The output will be an ephemeral "internal" key string suitable for the current session only.
Supported formats are:
RSAKeyPair elementThis supersedes the following functions:
RSA_ReadEncPrivateKeyRSA_ReadPrivateKeyInfoRSA_ReadPrivateKeyFromPFXThis VB6/VBA wrapper function returns the "internal" private key string given the filename and password
Public Function rsaReadPrivateKey(strKeyFileOrString As String, strPassword As String) As String ' Reads the private key from any supported private key file or PEM string ' Returns the key as an ephemeral base64 string or an empty string on error Dim nChars As Long ' How long is PrivateKey string? nChars = RSA_ReadAnyPrivateKey("", 0, strKeyFileOrString, strPassword, 0) If nChars <= 0 Then Exit Function End If ' Pre-dimension the string to receive data rsaReadPrivateKey = String(nChars, " ") ' Read in the Private Key nChars = RSA_ReadAnyPrivateKey(rsaReadPrivateKey, nChars, strKeyFileOrString, strPassword, 0) End Function
Dim strIntKey As String strIntKey = rsaReadAnyPrivateKey("AlicePrivRSASign.p8e", "password") Debug.Print strIntKey Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strIntKey)) ' Unencrypted key strIntKey = rsaReadAnyPrivateKey("AlicePrivRSASign.pri", "") Debug.Print strIntKey Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strIntKey)) ' Key in XML form strIntKey = rsaReadAnyPrivateKey("alice-pri.xml", "") Debug.Print strIntKey Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strIntKey))
Reads from a file or string containing a public key into an "internal" public key string.
Public Declare Function RSA_ReadAnyPublicKey Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strKeyFileOrString As String, ByVal nOptions As Long) As Long
nRet = RSA_ReadAnyPublicKey(strOutput, nOutChars, strKeyFileOrString, nOptions) As Long
long __stdcall RSA_ReadAnyPublicKey(char *szOutput, long nOutChars, const char *szKeyFileOrString, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function rsaReadAnyPublicKey (szKeyFileOrString As String, Optional nOptions As Long = 0) As String
static std::string dipki::Rsa::ReadPublicKey (const std::string &keyFileOrString)
static Rsa.read_public_key(keyfileorstr)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
This function will attempt to read the public key from "any" supported format. The output will be an ephemeral "internal" key string suitable for the current session only.
Supported formats are:
RSAKeyValue or RSAKeyPair element
To read in a public key from a PFX/p12 file, use RSA_ReadAnyPrivateKey
then RSA_PublicKeyFromPrivate.
This supersedes the following functions:
RSA_ReadPublicKeyRSA_GetPublicKeyFromCertThis VB6/VBA wrapper function returns the "internal" public key string from the specified file.
Public Function rsaReadPublicKey(strKeyFile As String) As String ' Reads the public key from any supported public key file or PEM string ' Returns the key as an ephemeral base64 string or an empty string on error Dim nChars As Long ' How long is key string? nChars = RSA_ReadAnyPublicKey("", 0, strKeyFile, 0) If nChars <= 0 Then Exit Function End If ' Pre-dimension the string to receive data rsaReadPublicKey = String(nChars, " ") ' Read in the Public Key nChars = RSA_ReadAnyPublicKey(rsaReadPublicKey, nChars, strKeyFile, 0) End Function
This example reads in an RSA public key in JSON JWK format.
Dim strJson As String Dim strPublicKey As String Dim nChars As Long ' RSA public key as a JSON string ' Ref: RFC 7517 JSON Web Key (JWK) Appendix A.1 ' NB quotation marks (") inside a VBA string are escaped as "". strJson = "{""kty"":""RSA""," & _ """n"": ""0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx" & _ "4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs" & _ "tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2" & _ "QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI" & _ "SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqb" & _ "w0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw""," & _ """e"":""AQAB""," & _ """alg"":""RS256""," & _ """kid"":""2011-04-29""}" Debug.Print strJson ' Read in the public key as an internal string ' How many characters? nChars = RSA_ReadAnyPublicKey(ByVal 0&, 0, strJson, 0) Debug.Print "RSA_ReadAnyPublicKey returns " & nChars strPublicKey = String(nChars, " ") nChars = RSA_ReadAnyPublicKey(strPublicKey, nChars, strJson, 0) ' Examine the key's properties Debug.Print "RSA key size = " & RSA_KeyBits(strPublicKey) & " bits" Debug.Print "Hash code = 0x" & Hex(RSA_KeyHashCode(strPublicKey))
{"kty":"RSA","n": "0vx7agoebGcQSuuPiLJXZptN9nndr [cut] JzKnqDKgw","e":"AQAB","alg":"RS256","kid":"2011-04-29"}
RSA_ReadAnyPublicKey returns 400
RSA key size = 2048 bits
Hash code = 0xDFC04E17
Dim strIntKey As String strIntKey = rsaReadAnyPublicKey("AlicePubRSA.pub") Debug.Print strIntKey Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strIntKey)) ' X.509 certificate strIntKey = rsaReadAnyPublicKey("AliceRSASignByCarl.cer") Debug.Print strIntKey Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strIntKey)) ' Key in XML form strIntKey = rsaReadAnyPublicKey("alice-pub.xml") Debug.Print strIntKey Debug.Print "KeyHashCode=0x" & Hex(RSA_KeyHashCode(strIntKey))
Reads from an encrypted PKCS#8 private key info file into an "internal" private key string.
[Superseded by RSA_ReadAnyPrivateKey.]
Public Declare Function RSA_ReadEncPrivateKey Lib "diCrPKI.dll"
(ByVal strPrivateKey As String, ByVal nOutChars As Long, ByVal strEpkFileName As String,
ByVal strPassword As String, ByVal nOptions As Long) As Long
nRet = RSA_ReadEncPrivateKey(strPrivateKey, nOutChars,
strEpkFileName, strPassword, nOptions) As Long
long __stdcall RSA_ReadEncPrivateKey(char *szOutput, long nOutChars, const char *szEpkFile, const char *szPassword, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Only PKCS-8 EncryptedPrivateKeyInfo data
using the rsaEncryption algorithm is supported.
The file must be either in binary BER-encoded format or PEM format.
RSA_SaveEncPrivateKey RSA_ReadPrivateKeyInfo RSA_SavePrivateKeyInfo RSA_GetPrivateKeyFromPFX
Reads a private key directly from an encrypted PFX/PKCS-12 file into an "internal" private key string. [Superseded by RSA_ReadAnyPrivateKey.]
Public Declare Function RSA_ReadPrivateKeyFromPFX Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strPfxFile As String, ByVal strPassword As String, ByVal nOptions As Long) As Long
nRet = RSA_ReadPrivateKeyFromPFX(strOutput, nOutChars, strPfxFile, strPassword, nOptions) As Long
long __stdcall RSA_ReadPrivateKeyFromPFX(char *szOutput, long nOutChars, const char *szPfxFile, const char *szPassword, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Rsa.ReadPrivateKeyFromPFX Method
This will read the private key from
the first pkcs8ShroudedKeyBag object it finds and can decrypt in the PFX file.
The result is a string in "internal" key string format valid only for the current session.
Call the function with an empty or NULL szOutput string or zero nOutChars parameter to find out the required length
of the output string. C/C++ users should add one to this value when allocating memory.
If you need the public key instead from a PFX file, then use this function followed by
RSA_PublicKeyFromPrivate().
If you just want to extract the encrypted private key and save directly as a pkcs-8 file, then use the
RSA_GetPrivateKeyFromPFX() function.
Dim strPfxFile As String Dim strPrivateKey As String Dim strPassword As String Dim nChars As Long Dim nCode As Long Dim nRet As Long strPfxFile = "bob.pfx" strPassword = "password" ' Read private key from PFX file into internal string form nChars = RSA_ReadPrivateKeyFromPFX("", 0, strPfxFile, strPassword, 0) If nChars <= 0 Then Exit Sub ' Catch error here strPrivateKey = String(nChars, " ") nChars = RSA_ReadPrivateKeyFromPFX(strPrivateKey, Len(strPrivateKey), strPfxFile, strPassword, 0) ' Display some info about it Debug.Print "Private key length = " & RSA_KeyBits(strPrivateKey) & " bits" nCode = RSA_KeyHashCode(strPrivateKey) Debug.Print "KeyHashCode=" & Hex(nCode) nRet = RSA_CheckKey(strPrivateKey, 0) Debug.Print "RSA_CheckKey returns " & nRet & ": (PKI_VALID_PRIVATEKEY=" & PKI_VALID_PRIVATEKEY & ")" ' Clean up strPrivateKey = wipeString(strPrivateKey) strPassword = wipeString(strPassword)
Private key length = 1024 bits KeyHashCode=6BCC120C RSA_CheckKey returns 0: (PKI_VALID_PRIVATEKEY=0)
RSA_GetPrivateKeyFromPFX RSA_ReadEncPrivateKey RSA_PublicKeyFromPrivate
Reads from an (unencrypted) PKCS-8 private key info file into an "internal" private key string.
[Superseded by RSA_ReadAnyPrivateKey.]
Public Declare Function RSA_ReadPrivateKeyInfo Lib "diCrPKI.dll"
(ByVal strPrivateKey As String, ByVal nOutChars As Long, ByVal strPriFileName As String,
ByVal nOptions As Long) As Long
nRet = RSA_ReadPrivateKeyInfo(strPrivateKey, nOutChars,
strPriFileName, nOptions) As Long
long __stdcall RSA_ReadPrivateKeyInfo(char *szOutput, long nOutChars, const char *szKeyFile, long nOptions);
PrivateKeyInfo file (or a string containing the key in PEM format).If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Only PKCS-8 PrivateKeyInfo files
specifying the rsaEncryption algorithm are supported
together with OpenSSL-compatible RSA PRIVATE KEY files.
Files may be in either binary BER/DER-encoded format or PEM format.
Call the function with an empty or NULL szOutput string or zero nOutChars parameter to find out the required length of
the output string. C/C++ users should add one to this value when allocating memory.
This example reads in Bob's unencrypted private key from the file
BobPrivRSAEncrypt.pri from [SMIME-EX] and saves in encrypted form using the
password "password". The default PBE algorithm pbeWithSHAAnd3-KeyTripleDES-CBC
is used with an iteration count of 1000.
Dim strPRIFile As String Dim strEPKFile As String Dim strPrivateKey As String Dim strPK1 As String Dim nKeyLen As String Dim nRet As Long ' Read in Bob's unencrypted PrivateKeyInfo data strPRIFile = "BobPrivRSAEncrypt.pri" nKeyLen = RSA_ReadPrivateKeyInfo("", 0, strPRIFile, 0) If nKeyLen <= 0 Then MsgBox "Failed to read Private Key file" Exit Sub End If strPrivateKey = String(nKeyLen, " ") nRet = RSA_ReadPrivateKeyInfo(strPrivateKey, nKeyLen, strPRIFile, 0) If nRet <= 0 Then MsgBox "Failed to read Private Key file" Exit Sub End If ' Now we save it with a password strEPKFile = "BobPrivRSAEncrypt.p8e" nRet = RSA_SaveEncPrivateKey(strEPKFile, strPrivateKey, 1000, "password", 0) Debug.Print "RSA_SaveEncPrivateKey returns " & nRet ' Check we can read it strPK1 = rsaReadPrivateKey(strEPKFile, "password") ' Sneak a look at the two key strings. ' CAUTION: _Never_ print these in a production system! Debug.Print strPK1 Debug.Print strPrivateKey ' To compare these strings, use the RSA_KeyHashCode function Debug.Print Hex(RSA_KeyHashCode(strPK1)) Debug.Print Hex(RSA_KeyHashCode(strPrivateKey)) If RSA_KeyHashCode(strPK1) = RSA_KeyHashCode(strPrivateKey) Then Debug.Print "Key string values match." Else Debug.Print "ERROR: key strings do not match." End If
RSA_ReadEncPrivateKey RSA_KeyHashCode
Reads from an RSA public key file into an "internal" public key string.
[Superseded by RSA_ReadAnyPublicKey.]
Public Declare Function RSA_ReadPublicKey Lib "diCrPKI.dll"
(ByVal strPublicKey As String, ByVal nOutChars As Long, ByVal strKeyFileName As String,
ByVal nOptions As Long) As Long
nRet = RSA_ReadPublicKey(strPublicKey, nOutChars,
strKeyFileName, nOptions) As Long
long __stdcall RSA_ReadPublicKey(char *szOutput, long nOutChars, const char *szPubKeyFile, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function rsaReadPublicKey (szKeyFileOrString As String, Optional nOptions As Long = 0) As String
Both PKCS-1 RSAPublicKey and OpenSSL SubjectPublicKeyInfo formats are supported.
The file can be in binary BER-encoded format or PEM format, or be passed as a string containing the data in PEM format.
Call the function with an empty or NULL szOutput string or zero nOutChars parameter to find out the required length of
the output string. C/C++ users should add one to this value when allocating memory.
RSA_ReadAnyPublicKey RSA_SavePublicKey RSA_GetPublicKeyFromCert
Save an internal RSA key string to an encrypted key file.
Public Declare Function RSA_SaveEncKey Lib "diCrPKI.dll" (ByVal strFileOut As String, ByVal strIntKeyString As String, ByVal strPassword As String, ByVal strParams As String, ByVal nOptions As Long) As Long
nRet = RSA_SaveEncKey(strFileOut, strIntKeyString, strPassword, strParams, nOptions) As Long
long __stdcall RSA_SaveEncKey(const char *szFileOut, const char *szIntKeyString, const char *szPassword, const char *szParams, long nOptions);
"" for defaults.
Otherwise include a set of attribute-value pairs separated by a semi-colon ";" to set options from the following
count=<nnn> to set the iteration count in the encrypted private key used in the PBKDF method,
e.g. "count=5000;" [default=2048]
prf=<hmac-name> to change the HMAC algorithm used in the PBKDF2 method,
e.g. "prf=hmacWithSHA256;" [default=hmacwithSHA1]
{hmacWithSHA1|hmacWithSHA224|hmacWithSHA256|hmacWithSHA384|hmacWithSHA512}.
pbeWithSHAAnd3-KeyTripleDES-CBC from PKCS12 (default)des-EDE3-CBCaes128-CBCaes192-CBCaes256-CBCENCRYPTED PRIVATE KEY PEM-format file (default is binary BER-encoded format). If successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function rsaSaveEncKey (szOutputFile As String, szKeyStr As String, szPassword As String, Optional szParams As String = "", Optional nOptions As Long = 0) As Long
static int dipki::Rsa::SaveEncKey (const std::string &outputFile, const std::string &keyStr, const std::string &password, PbeScheme pbes=PbeScheme::Default, const std::string ¶mString="", Format fileFormat=Format::Binary)
static Rsa.save_enc_key(outputfile, intkeystr, password, pbescheme=0, params='', fileformat=0)
Saves a private key string to a PKCS-8 encrypted private key info file.
Public Declare Function RSA_SaveEncPrivateKey Lib "diCrPKI.dll"
(ByVal strOutputFile As String, ByVal strPrivateKey As String, ByVal nCount As Long,
ByVal strPassword As String, ByVal nOptions As Long) As Long
nRet = RSA_SaveEncPrivateKey(strOutputFile, strPrivateKey,
nCount, strPassword, nOptions) As Long
long __stdcall RSA_SaveEncPrivateKey(const char *szFileOut, const char *szKeyString, long nCount, const char *szPassword, long nOptions);
pbeWithSHAAnd3-KeyTripleDES-CBC (default)des-EDE3-CBCaes128-CBCaes192-CBCaes256-CBCENCRYPTED PRIVATE KEY PEM-format file (default is binary BER-encoded format).If successful, the return value is zero; otherwise it returns a nonzero error code.
Rsa.SaveEncPrivateKey Method
Rsa.SaveEncPrivateKey Method
The default is to save as a binary BER-encoded PKCS-8 EncryptedPrivateKeyInfo file. If the PKI_KEY_FORMAT_PEM option is added, the file be will in PEM format. The PEM encrypted private key format uses the header and footer lines:
-----BEGIN ENCRYPTED PRIVATE KEY----- -----END ENCRYPTED PRIVATE KEY-----
This example reads Carl's unencrypted private key info file from
[SMIME-EX] and saves in encrypted format with the password "password".
It then checks that the two keys match by using the
RSA_KeyHashCode function.
Dim strPRIFile As String Dim strEPKFile As String Dim strPrivateKey As String Dim strPK1 As String Dim nChars As String Dim nRet As Long strPRIFile = "CarlPrivRSASign.pri" ' Read in Carl's unencrypted PrivateKeyInfo data nChars = RSA_ReadPrivateKeyInfo("", 0, strPRIFile, 0) If nChars <= 0 Then MsgBox "Failed to read Private Key file" Exit Sub End If ' Dimension the string to receive it - IMPORTANT strPrivateKey = String(nChars, " ") ' Read in as an "internal" key string nRet = RSA_ReadPrivateKeyInfo(strPrivateKey, nChars, strPRIFile, 0) If nRet <= 0 Then MsgBox "Failed to read Private Key file" Exit Sub End If Debug.Print "Private key length is " & RSA_KeyBits(strPrivateKey) & " bits" ' Now save it in PKCS#8 encrypted form with a password strEPKFile = "CarlPrivRSASign.p8e" nRet = RSA_SaveEncPrivateKey(strEPKFile, strPrivateKey, 1000, "password", 0) Debug.Print "RSA_SaveEncPrivateKey returns " & nRet & " (expected 0)" ' Check we can read it (note easier wrapper function) strPK1 = rsaReadPrivateKey(strEPKFile, "password") If Len(strPK1) > 0 Then Debug.Print "Encrypted private key is " & RSA_KeyBits(strPK1) & " bits" Else MsgBox "Unable to read encrypted private key" End If ' To compare these strings, use the RSA_KeyHashCode function Debug.Print "HashCode(original prikeyinfo) =" & Hex(RSA_KeyHashCode(strPrivateKey)) Debug.Print "HashCode(encrypted prikeyinfo)=" & Hex(RSA_KeyHashCode(strPK1)) If RSA_KeyHashCode(strPK1) = RSA_KeyHashCode(strPrivateKey) Then Debug.Print "OK, Key string values match." Else Debug.Print "ERROR: key strings do not match." End If
This should give the output
Private key length is 1024 bits RSA_SaveEncPrivateKey returns 0 (expected 0) Encrypted private key is 1024 bits HashCode(original prikeyinfo) =A937B1B5 HashCode(encrypted prikeyinfo)=A937B1B5 OK, Key string values match.
Saves a private key string to an (unencrypted) PKCS-8 private key info file.
Public Declare Function RSA_SavePrivateKeyInfo Lib "diCrPKI.dll"
(ByVal strOutputFile As String, ByVal strPrivateKey As String,
ByVal nOptions As Long) As Long
nRet = RSA_SavePrivateKeyInfo(strOutputFile, strPrivateKey,
nOptions) As Long
long __stdcall RSA_SavePrivateKeyInfo(const char *szFileOut, const char *szKeyString, long nOptions);
PRIVATE KEY fileRSA PRIVATE KEY PEM fileIf successful, the return value is zero; otherwise it returns a nonzero error code.
static Rsa.save_key(outputfile, keystr, fileformat=0)
Any existing file of the specified name will be overwritten without warning. Saves by default as a binary BER-encoded file compatible with the PKCS-8 PrivateKeyInfo format. The PEM key format saved with the PKI_KEY_FORMAT_PEM option uses the header and footer lines:
-----BEGIN PRIVATE KEY----- -----END PRIVATE KEY-----
The OpenSSL-compatible PEM key format saved with the PKI_KEY_FORMAT_SSL option uses the header and footer lines:
-----BEGIN RSA PRIVATE KEY----- -----END RSA PRIVATE KEY-----
and is compatible with the PKCS-1 RSAPrivateKey format.
Dim strEPKFile As String
Dim strPRIFile As String
Dim strPEMFile As String
Dim strPassword As String
Dim strPrivateKey As String
Dim nRet As Long
strEPKFile = "rsa508.p8e"
strPRIFile = "rsa508.pri"
strPEMFile = "rsa508.pem"
strPassword = "password"
' Read in the deciphered private key string
strPrivateKey = rsaReadPrivateKey(strEPKFile, strPassword)
If Len(strPrivateKey) = 0 Then
MsgBox "Unable to retrieve private key"
Exit Function
End If
Debug.Print strPrivateKey
' Save as unencrypted PrivateKeyInfo file
nRet = RSA_SavePrivateKeyInfo(strPRIFile, strPrivateKey, 0)
Debug.Print "RSA_SavePrivateKeyInfo returns " & nRet
' Save as unencrypted PEM-format file
nRet = RSA_SavePrivateKeyInfo(strPEMFile, strPrivateKey, PKI_KEY_FORMAT_PEM)
Debug.Print "RSA_SavePrivateKeyInfo returns " & nRet
Saves a public key string to PKCS-1 public key file.
Public Declare Function RSA_SavePublicKey Lib "diCrPKI.dll"
(ByVal strOutputFile As String, ByVal strPublicKey As String,
ByVal nOptions As Long) As Long
nRet = RSA_SavePublicKey(strOutputFile, strPublicKey,
nOptions) As Long
long __stdcall RSA_SavePublicKey(const char *szFileOut, const char *szKeyString, long nOptions);
"RSA PUBLIC KEY" file"PUBLIC KEY" PEM fileIf successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function rsaSaveKey (szOutputFile As String, szKeyStr As String, Optional nOptions As Long = 0) As Long
static int dipki::Rsa::SaveKey (const std::string &outputFile, const std::string &keyStr, Format fileFormat=Format::Binary)
Any existing file of the specified name will be overwritten without warning. Saves by default as binary DER/BER-encoded PKCS-1 RSAPublicKey data. The file saved with the PKI_KEY_FORMAT_PEM option is the same data in PEM format with header and footer lines:
-----BEGIN RSA PUBLIC KEY----- -----END RSA PUBLIC KEY-----
The file saved with the PKI_KEY_FORMAT_SSL option is compatible with the format used by OpenSSL. The data is saved as X.509 SubjectPublicKeyInfo format encoded with header and footer lines:
-----BEGIN PUBLIC KEY----- -----END PUBLIC KEY-----
The OpenSSL format key is saved with "Unix" line endings and a line length of strictly 64 characters.
You can use this function to extract a public key from a private key. Just pass the internal private key string instead of the public key string.
See the example in RSA_GetPublicKeyFromCert.
RSA_ReadPublicKey RSA_GetPublicKeyFromCert
Creates an XML string representation of an RSA internal key string.
Public Declare Function RSA_ToXMLString Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nOutChars As Long, ByVal strKeyString As String,
ByVal nOptions As Long) As Long
nRet = RSA_ToXMLString(strOutput, nOutChars,
strKeyString, nOptions) As Long
long __stdcall RSA_ToXMLString(char *szOutput, long nOutChars, const char *szKeyString, long nOptions);
RSAKeyValue for public key and RSAKeyPair for private key)RSAKeyValue format (instead of W3C RSAKeyPair)RSAKeyValue from a private key)hexBinary formatIf successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function rsaToXMLString (szKeyString As String, Optional nOptions As Long = 0) As String
Rsa.ToXMLString Method (String, Rsa.XmlOptions)
static std::string dipki::Rsa::ToXMLString (const std::string &keyStr, XmlOptions opts=XmlOptions::None, const std::string &prefix="")
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
Both public and private key data can be output. The key must have been read first into an internal key string using one of the other RSA key input functions in this toolkit.
If the internal key is a public key, or if the PKI_XML_EXCLPRIVATE option is used with a private key,
the output will always be a RSAKeyValue element
containing just <Modulus> and <Exponent> elements
as per [XMLDSIG].
If the internal key is a private key and the PKI_XML_EXCLPRIVATE option is not used,
the default output will be a a XKMS-conforming RSAKeyPair element with the private key
parameters included. Including the PKI_XML_RSAKEYVALUE option will force a .NET-compatible
RSAKeyValue element instead.
The only difference between RSAKeyPair and RSAKeyValue is in the name of the
outer XML element. The default behaviour is to comply with the W3C standards
[XKMS] and [XMLDSIG].
Users who wish to export a private key to use in the .NET world will
probably want to use the PKI_XML_RSAKEYVALUE option.
The PKI_XML_HEXBINARY option will output the binary data in hexBinary encoding format
instead of base64. This latter format is not in conformance with any W3C standard, but is provided to allow
users to see the data in more readable hex format. Such a format can be read by
this toolkit's RSA_FromXMLString() function,
but don't try using it anywhere else.
This example reads in a private key from a encrypted private key file and then converts to an XML string in the .NET-compatible format.
Dim strEPKFile As String
Dim strPassword As String
Dim strPrivateKey As String
Dim strXML As String
Dim nLen As Long
strEPKFile = "AlicePrivRSASign.p8e"
strPassword = "password"
' Read in the deciphered private key string in our internal format
strPrivateKey = rsaReadPrivateKey(strEPKFile, strPassword)
If Len(strPrivateKey) = 0 Then
MsgBox "Unable to retrieve private key"
Exit Function
End If
Debug.Print "INTKEY=" & strPrivateKey
' Convert to XML
nLen = RSA_ToXMLString("", 0, strPrivateKey, PKI_XML_RSAKEYVALUE)
' pre-dimension first
strXML = String(nLen, " ")
nLen = RSA_ToXMLString(strXML, Len(strXML), strPrivateKey, PKI_XML_RSAKEYVALUE)
strXML = Left(strXML, nLen)
Debug.Print "XML=" & strXML
The output should look like this (only longer):
INTKEY=MIICXAIBAAKBgQDgiXM5jdj19eiHdjl/ ... XML=<RSAKeyValue><Modulus>4IlzOY3Y9fXoh ... +yRRKt/IQ==</D></RSAKeyValue>
Dim strPrivateKey As String
strPrivateKey = rsaReadPrivateKey("AlicePrivRSASign.p8e", "password")
Debug.Print rsaToXMLString(strPrivateKey, 0)
Debug.Print rsaToXMLString(strPrivateKey, PKI_XML_EXCLPRIVATE Or PKI_XML_HEXBINARY)
Debug.Print rsaToXMLStringEx(strPrivateKey, "ds", PKI_XML_EXCLPRIVATE)
' Now derive internal private key string from XML
Dim strXML As String
Dim strKey As String
strXML = rsaToXMLString(strPrivateKey)
strKey = rsaFromXMLString(strXML)
Debug.Print "Key length = " & RSA_KeyBits(strKey) & " bits"
Creates an XML string representation of an RSA internal key string with option to add a namespace prefix.
Public Declare Function RSA_ToXMLStringEx Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nOutChars As Long, ByVal strKeyString As String,
ByVal strPrefix As String, ByVal nOptions As Long) As Long
nRet = RSA_ToXMLStringEx(strOutput, nOutChars,
strKeyString, "ds", nOptions) As Long
long __stdcall RSA_ToXMLStringEx(char *szOutput, long nOutChars, const char *szKeyString, const char *szPrefix, long nOptions);
RSAKeyValue for public key and RSAKeyPair for private key)RSAKeyValue format (instead of W3C RSAKeyPair)RSAKeyValue from a private key)hexBinary formatIf successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function rsaToXMLStringEx (szKeyString As String, szPrefix As String, Optional nOptions As Long = 0) As String
Rsa.ToXMLString Method (String, String, Rsa.XmlOptions)
static Rsa.to_xmlstring(keystr, opts=0, prefix='')
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
Use this extended function to add a namespace prefix to all elements in the XML output;
for example, <ds:RSAKeyValue>.
Note that it's up to the user to map the prefix to a URI somewhere in the final XML document
(for reference, the correct form is xmlns:ds="http://www.w3.org/2000/09/xmldsig#").
See also the remarks for RSA_ToXMLString.
nLen = RSA_ToXMLStringEx("", 0, strPrivateKey, "ds", PKI_XML_EXCLPRIVATE) ' pre-dimension first strXML = String(nLen, " ") nLen = RSA_ToXMLStringEx(strXML, Len(strXML), strPrivateKey, "ds", PKI_XML_EXCLPRIVATE) strXML = Left(strXML, nLen) Debug.Print "XML=" & strXML
<ds:RSAKeyValue><ds:Modulus>uV3GoY7...Yb+F3Q==</ds:Modulus><ds:Exponent>AQAB</ds:Exponent></ds:RSAKeyValue>
Dim strPrivateKey As String
strPrivateKey = rsaReadPrivateKey("AlicePrivRSASign.p8e", "password")
Debug.Print rsaToXMLString(strPrivateKey, 0)
Debug.Print rsaToXMLString(strPrivateKey, PKI_XML_EXCLPRIVATE Or PKI_XML_HEXBINARY)
Debug.Print rsaToXMLStringEx(strPrivateKey, "ds", PKI_XML_EXCLPRIVATE)
' Now derive internal private key string from XML
Dim strXML As String
Dim strKey As String
strXML = rsaToXMLString(strPrivateKey)
strKey = rsaFromXMLString(strXML)
Debug.Print "Key length = " & RSA_KeyBits(strKey) & " bits"
Compute a signature value over data in a byte array.
Public Declare Function SIG_SignData Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByRef lpData As Byte, ByVal nDataLen As Long, ByVal strKeyFile As String, ByVal strPassword As String, ByVal strAlgName As String, ByVal nOptions As Long) As Long
nRet = SIG_SignData(strOutput, nOutChars, lpData(0), nDataLen,
strKeyFile, strPassword, strAlgName, nOptions)
long __stdcall SIG_SignData(char *szOutput, long nOutChars, const unsigned char *lpData, long nDataLen, const char *szKeyFile, const char *szPassword, const char *szAlgName, long nOptions);
"" if not required.r||s)
hLen, the length of the output of the hash function (default).If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function sigSignData (lpData() As Byte, szKeyFile As String, szPassword As String, szAlgName As String, Optional nOptions As Long = 0) As String
Sig.SignData Method
Sig.SignDigest Method
static std::string dipki::Sig::SignData (const bvec_t &data, const std::string &keyFileOrString, const std::string &password="", Alg alg=Alg::Default, Encoding encoding=Encoding::Base64, SigOptions opts=SigOptions::None)
static Sig.sign_digest(digest, keyfile, password, alg, opts=Opts.DEFAULT, encoding=Encoding.DEFAULT)
static Sig.sign_data(data, keyfile, password, alg, opts=Opts.DEFAULT, encoding=Encoding.DEFAULT)
static Sig.sign_digest(digest, keyfile, password, alg, opts=Opts.DEFAULT, encoding=Encoding.DEFAULT)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
Computes the signature value over the input data (or its digest value) using the private key provided.
The default output is a continuous string of base64 characters
suitable to include in the <SignatureValue> node of an XML-DSIG document.
Alternative output encodings (base64url and hex) can be specified using the PKI_ENCODE_ options.
The PKI_SIG_USEDIGEST option cannot be used with Ed25519 or Ed448. The data to be signed must be passed in toto to the signature function. All options except the PKI_ENCODE_ options are ignored for the Ed25519 and Ed448 algorithms.
Dim strSignature As String Dim nChars As Long Dim strData As String Dim abData() As Byte Dim nDataLen As Long Dim strKeyFile As String Dim strPassword As String Dim strAlgName As String ' 1) Input data = three-character ASCII string "abc" strData = "abc" strKeyFile = "AlicePrivRSASign.p8e" strPassword = "password" ' CAUTION: do not hard-code passwords! strAlgName = "sha1WithRSAEncryption" ' Convert ASCII string to byte array abData = StrConv(strData, vbFromUnicode) nDataLen = Len(strData) ' Find required length of output string nChars = SIG_SignData("", 0, abData(0), nDataLen, strKeyFile, strPassword, _ strAlgName, 0) Debug.Print "SIG_SignData returns " & nChars & " (expected >0)" ' Allocate memory for output string strSignature = String(nChars, " ") nChars = SIG_SignData(strSignature, Len(strSignature), abData(0), nDataLen, _ strKeyFile, strPassword, strAlgName, 0) ' Output base64 signature value Debug.Print "SIG=" & strSignature ' 2) Use digest value instead of original data ' Convert known value of SHA-1("abc") in hex to an array of bytes abData = cnvBytesFromHexStr("a9993e364706816aba3e25717850c26c9cd0d89d") nDataLen = PKI_SHA1_BYTES ' Find required length of output string nChars = SIG_SignData("", 0, abData(0), nDataLen, strKeyFile, strPassword, _ strAlgName, PKI_SIG_USEDIGEST) Debug.Print "SIG_SignData returns " & nChars & " (expected >0)" ' Allocate memory for output string strSignature = String(nChars, " ") nChars = SIG_SignData(strSignature, Len(strSignature), abData(0), nDataLen, _ strKeyFile, strPassword, strAlgName, PKI_SIG_USEDIGEST) ' Output base64 signature value Debug.Print "SIG=" & strSignature
This uses Alice's encrypted private key to sign the ASCII string "abc" using
both the original string data (converted to a byte array)
and its digest value. The output should be
SIG_SignData returns 172 (expected >0) SIG=YK1aePtKQDDsVCyJdM0V9VOE6DZVTO3Z ... AmHH6QIsDZ8R8= SIG_SignData returns 172 (expected >0) SIG=YK1aePtKQDDsVCyJdM0V9VOE6DZVTO3Z ... AmHH6QIsDZ8R8=
The following example uses an elliptic curve key to produce an ECDSA signature in hex form using the "Deterministic" algorithm from [RFC6979]
Dim nChars As Long Dim nBits As Long Dim strIntKey As String Dim strHexKey As String Dim strCurveName As String Dim strSignature As String Dim strData As String Dim abData() As Byte Dim nDataLen As Long Dim strAlgName As String ' Ref: [RFC6979] "Deterministic Usage of the DSA and ECDSA" ' A.2.3. ECDSA, 192 Bits (Prime Field) ' 1. READ IN PRIVATE KEY IN (HEX,CURVENAME) FORMAT strHexKey = "6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4" strCurveName = "P-192" Debug.Print "KEYHEX: " & strHexKey Debug.Print "CURVE: " & strCurveName ' Find required length of internal key string nChars = ECC_ReadKeyByCurve("", 0, strHexKey, strCurveName, 0) Debug.Print "ECC_ReadKeyByCurve returns " & nChars & " (expected +ve)" ' Dimension the string to receive output strIntKey = String(nChars, " ") ' Read into internal key string nChars = ECC_ReadKeyByCurve(strIntKey, Len(strIntKey), strHexKey, strCurveName, 0) 'Debug.Print "INTKEY: " & strIntKey ' Check we got the bitlength we expected nBits = ECC_QueryKey("", 0, strIntKey, "keyBits", 0) Debug.Print "NBITS=" & nBits ' 2. PREPARE INPUT DATA AS AN ARRAY OF BYTES strData = "test" strAlgName = "ecdsaWithSHA1" ' Convert ASCII string to byte array abData = StrConv(strData, vbFromUnicode) nDataLen = Len(strData) '3. SIGN IT USING DETERMINISTIC ALGORITHM FROM [RFC6979] ' Find required length of output string nChars = SIG_SignData("", 0, _ abData(0), nDataLen, strIntKey, "", _ strAlgName, PKI_SIG_DETERMINISTIC Or PKI_ENCODE_HEX) Debug.Print "SIG_SignData returns " & nChars & " (expected >0)" ' Allocate memory for output string strSignature = String(nChars, " ") nChars = SIG_SignData(strSignature, Len(strSignature), _ abData(0), nDataLen, strIntKey, "", _ strAlgName, PKI_SIG_DETERMINISTIC Or PKI_ENCODE_HEX) ' Output hex signature value Debug.Print "SIG=" & strSignature
KEYHEX: 6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4 CURVE: P-192 ECC_ReadKeyByCurve returns 164 (expected +ve) NBITS=192 SIG_SignData returns 96 (expected >0) SIG=0f2141a0ebbc44d2e1af90a50ebcfce5e197b3b7d4de036deb18bc9e1f3d7387500cb99cf5f7c157070a8961e38700b7
Dim lpData() As Byte
Dim strSig As String
lpData = StrConv("abc", vbFromUnicode)
strSig = sigSignData(lpData, "AlicePrivRSASign.p8e", "password", "sha1WithRSAEncryption")
Debug.Print "SIG=" & strSig
Debug.Print "OK =" & "YK1aePtKQDDsVCyJdM0V9VOE6DZVTO3Z ... AmHH6QIsDZ8R8="
Compute a signature value over data in a file.
Public Declare Function SIG_SignFile Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strDataFile As String, ByVal strKeyFile As String, ByVal strPassword As String, ByVal strAlgName As String, ByVal nOptions As Long) As Long
nRet = SIG_SignFile(strOutput, nOutChars, strDataFile, strKeyFile, strPassword, strAlgName, nOptions)
long __stdcall SIG_SignFile(char *szOutput, long nOutChars, const char *szDataFile, const char *szKeyFile, const char *szPassword, const char *szAlgName, long nOptions);
"" if not required.r||s)
hLen, the length of the output of the hash function (default).If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function sigSignFile (szDataFile As String, szKeyFile As String, szPassword As String, szAlgName As String, Optional nOptions As Long = 0) As String
static std::string dipki::Sig::SignFile (const std::string &dataFile, const std::string &keyFileOrString, const std::string &password="", Alg alg=Alg::Default, Encoding encoding=Encoding::Base64, SigOptions opts=SigOptions::None)
static Sig.sign_file(datafile, keyfile, password, alg, opts=Opts.DEFAULT, encoding=Encoding.DEFAULT)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
This function is identical to SIG_SignData except the data to be signed is in a file.
The Ed25519 and Ed448 signature algorithms are not available with this function. To sign using Ed25519 or Ed448, read in the file to a byte array and use SIG_SignData.
Dim strSignature As String Dim strDataFile As String Dim strKeyFile As String Dim strPassword As String Dim nChars As Long Dim nOption As Long 'Input data = file containing the three bytes 'a', 'b', 'c' strDataFile = "abc.txt" strKeyFile = "AlicePrivRSASign.p8e" strPassword = "password" ' CAUTION: do not hard-code passwords! nOption = PKI_SIG_SHA256RSA ' Use option instead of string ' Find required length of output string nChars = SIG_SignFile("", 0, strDataFile, strKeyFile, strPassword, "", nOption) Debug.Print "SIG_SignFile returns " & nChars & " (expected >0)" ' Allocate memory for output string strSignature = String(nChars, " ") nChars = SIG_SignFile(strSignature, Len(strSignature), strDataFile, strKeyFile, strPassword, "", nOption) ' Output base64 signature value Debug.Print "SIG=" & strSignature
This uses Alice's encrypted private key to sign a file using sha256WithRSAEncryption. The output should be
SIG_SignFile returns 172 (expected >0) SIG=tLy6hJadL4w9JI/A/qLCG0V...peD1VHSzgu/qirjOaA=
Dim strSig As String
strSig = sigSignFile("abc.txt", "AlicePrivRSASign.p8e", "password", "", PKI_SIG_SHA256RSA)
Debug.Print "SIG=" & strSig
Debug.Print "OK =" & "tLy6hJadL4w9JI/A/qLCG0V...peD1VHSzgu/qirjOaA="
Verify a signature value over data in a byte array.
Public Declare Function SIG_VerifyData Lib "diCrPKI.dll" (ByVal strSignature As String, ByRef lpData As Byte, ByVal nDataLen As Long, ByVal strCertOrKeyFile As String, ByVal strAlgName As String, ByVal nOptions As Long) As Long
nRet = SIG_VerifyData(strSignature, lpData(0), nDataLen, strCertOrKeyFile, strAlgName, nOptions)
long __stdcall SIG_VerifyData(const char *szSignature, const unsigned char *lpData, long nDataLen, const char *szCertOrKeyFile, const char *szAlgName, long nOptions);
Zero (0) if the signature is valid; otherwise it returns a negative error code.
Public Function sigVerifyData (szSignature As String, lpData() As Byte, szCertOrKey As String, szAlgName As String, Optional nOptions As Long = 0) As Long
Sig.VerifyData Method
Sig.VerifyDigest Method
static bool dipki::Sig::VerifyData (const std::string &sigStr, const bvec_t &data, const std::string &certOrKey, Alg alg=Alg::Default, VerifyOpts opts=VerifyOpts::Default)
static Sig.digest_is_verified(sig, digest, certorkey, alg, verifyopts=VerifyOpts.DEFAULT)
static Sig.data_is_verified(sig, data, certorkey, alg, verifyopts=VerifyOpts.DEFAULT)
static Sig.digest_is_verified(sig, digest, certorkey, alg, verifyopts=VerifyOpts.DEFAULT)
A signature value is considered valid if it can be decrypted by the public key in szCertOrKeyFile and the digest of the data matches the original digest of the data in the signature. The signature algorithm and hash algorithm used to create the signature value must be provided.
For RSA-PSS, the MGF hash algorithm is assumed to be the same as the signature hash algorithm (see RSA signature and encryption schemes).
If the signature was created using mgf1SHA1 with a signature hash algorithm other than SHA-1, then you must add the option PKI_MGF_MGF1SHA1.
Other combinations of signature hash algorithm/MGF hash algorithm are not supported.
The PKI_SIG_USEDIGEST option cannot be used with Ed25519 or Ed448. The data to be verified must be passed in toto to the verify function.
Dim strSignature As String Dim strData As String Dim abData() As Byte Dim nDataLen As Long Dim strCertFile As String Dim strAlgName As String Dim nRet As Long ' Signature to be verified strSignature = _ "YK1aePtKQDDsVCyJdM0V9VOE6DZVTO3ZoyLV9BNcYmep0glwxU5mUQcLAUTUOETImTIN2Pp4Gffr" & _ "xqdxUoczLshnXBNhg7P4ofge+WlBgmcTCnVv27LHHZpmdEbjTg6tnPMb+2b4FvMZ0LfkMKXyiRVTmG4A" & _ "NyAmHH6QIsDZ8R8=" ' Data to be verified against signature = three-character ASCII string "abc" strData = "abc" strCertFile = "AliceRSASignByCarl.cer" strAlgName = "sha1WithRSAEncryption" ' Convert ASCII string to byte array abData = StrConv(strData, vbFromUnicode) nDataLen = Len(strData) ' Verify the signature... nRet = SIG_VerifyData(strSignature, abData(0), nDataLen, strCertFile, strAlgName, 0) Debug.Print "SIG_VerifyData returns " & nRet & " (expecting 0)"
Verify a signature value over data in a file.
Public Declare Function SIG_VerifyFile Lib "diCrPKI.dll" (ByVal strSignature As String, ByVal strDataFile As String, ByVal strCertOrKeyFile As String, ByVal strAlgName As String, ByVal nOptions As Long) As Long
nRet = SIG_VerifyFile(strSignature, strDataFile, strCertOrKeyFile, strAlgName, nOptions)
long __stdcall SIG_VerifyFile(const char *szSignature, const char *szDataFile, const char *szCertOrKeyFile, const char *szAlgName, long nOptions);
Zero (0) if the signature is valid; otherwise it returns a negative error code.
static bool dipki::Sig::VerifyFile (const std::string &sigStr, const std::string &dataFile, const std::string &certOrKey, Alg alg=Alg::Default, VerifyOpts opts=VerifyOpts::Default)
static Sig.file_is_verified(sig, datafile, certorkey, alg, verifyopts=VerifyOpts.DEFAULT)
This function is identical to SIG_VerifyData except the data to be verified is in a file.
The Ed25519 and Ed448 signature algorithms are not available with this function. To verify using Ed25519 or Ed448, read in the file to a byte array and use SIG_VerifyData.
Dim strSignature As String Dim strDataFile As String Dim strCertFile As String Dim strAlgName As String Dim nRet As Long ' Signature to be verified strSignature = _ "tLy6hJadL4w9JI/A/qLCG0Vz1fWPIrPMWD8NGmA5wP7HHlUID54elztUYrpdm9RFeh0RCMJ618dw" & _ "BpgIutuZg2qQ2i9uMUYB0DvZvkyeD6MqmtVa4ihgc9SLqhigKeP+KB7voEi7PH3hpEr9Wa3kn4mb" & _ "PpeD1VHSzgu/qirjOaA=" ' File to be verified against signature = three-character ASCII string "abc" strDataFile = "abc.txt" strCertFile = "AliceRSASignByCarl.cer" strAlgName = "sha256WithRSAEncryption" ' Verify the signature over the data in the file... nRet = SIG_VerifyFile(strSignature, strDataFile, strCertFile, strAlgName, 0) Debug.Print "SIG_VerifyFile returns " & nRet & " (expecting 0)"
SIG_VerifyFile returns 0 (expecting 0)
Extract the body from an S/MIME entity.
Public Declare Function SMIME_Extract Lib "diCrPKI.dll" (ByVal strFileOut As String, ByVal strFileIn As String, ByVal nOptions As Long) As Long
nRet = SMIME_Extract(strFileOut, strFileOut, nOptions)
long __stdcall SMIME_Extract(const char *szFileOut, const char *szFileIn, long nOptions);
A positive number giving the size of the output file in bytes; or a negative error code.
static int dipki::Smime::Extract (const std::string &outputFile, const std::string &inputFile, Encoding encoding=Encoding::Default)
static Smime.extract(outputfile, inputfile, opts=0)
This is designed to extract the body from an S/MIME entity with a content type of application/pkcs7-mime
with base64 or binary transfer encoding.
In practice, it will extract the body from almost any type of S/MIME (or MIME) file,
except one with quoted-printable transfer encoding.
nRet = SMIME_Extract("cmsalice2bob-extracted.p7m", "cmsalice2bob-smime-env.txt", 0)
In this example, the input S/MIME file cmsalice2bob-smime-env.txt was created from a
CMS enveloped-data file using SMIME_Wrap.
The output should be a binary file identical to the original binary CMS file.
Query an S/MIME entity.
Public Declare Function SMIME_Query Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strFileIn As String, ByVal strQuery As String, ByVal nOptions As Long) As Long
nRet = SMIME_Query(strFileOut, strFileOut, strQuery, nOptions)
long __stdcall SMIME_Query(char *szOutput, long nOutChars, const char *szFileIn, const char *szQuery, long nOptions);
If successful, the return value is a positive number indicating the number of characters (bytes) in the output string, or number of characters required if nOutChars was set to zero. If the item queried cannot be found, the return value is zero. If there is an error (e.g. invalid input), it returns a negative error code.
Public Function smimeQuery (szFileIn As String, szQuery As String, Optional nOptions As Long = 0) As String
static std::string dipki::Smime::Query (const std::string &inputFile, const std::string &query)
static Smime.query(filename, query)
Valid queries are (case-insensitive):
| Query String | Returns |
|---|---|
content-type | Value of Content-Type, e.g. "application/pkcs7-mime" |
smime-type | Value of smime-type parameter of Content-Type, e.g. "enveloped-data" |
encoding | Value of Content-Transfer-Encoding, e.g. "base64" |
name | Value of name parameter of Content-Type, e.g. "smime.p7m" |
filename | Value of filename parameter of Content-Disposition, e.g. "smime.p7m" |
If no value is found corresponding to the query then the zero-length empty string "" is output.
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
Dim strQuery As String Dim strOutput As String Dim nRet As Long Dim strFileIn As String strFileIn = "cmsalice2bob-smime-env.txt" Debug.Print "FILE: " & strFileIn ' Make a buffer large enough to receive output strOutput = String(512, " ") strQuery = "content-type" nRet = SMIME_Query(strOutput, Len(strOutput), strFileIn, strQuery, 0) If nRet <= 0 Then Exit Sub ' catch error Debug.Print strQuery & "=" & Left(strOutput, nRet) strQuery = "smime-type" nRet = SMIME_Query(strOutput, Len(strOutput), strFileIn, strQuery, 0) If nRet <= 0 Then Exit Sub ' catch error Debug.Print strQuery & "=" & Left(strOutput, nRet) strQuery = "encoding" nRet = SMIME_Query(strOutput, Len(strOutput), strFileIn, strQuery, 0) If nRet <= 0 Then Exit Sub ' catch error Debug.Print strQuery & "=" & Left(strOutput, nRet) strQuery = "filename" nRet = SMIME_Query(strOutput, Len(strOutput), strFileIn, strQuery, 0) If nRet <= 0 Then Exit Sub ' catch error Debug.Print strQuery & "=" & Left(strOutput, nRet)
FILE: cmsalice2bob-smime-env.txt content-type=application/pkcs7-mime smime-type=enveloped-data encoding=base64 filename=smime.p7m
Dim strFileIn As String Dim strQuery As String strFileIn = "cmsalice2bob-smime-env.txt" Debug.Print "FILE: " & strFileIn strQuery = "content-type" Debug.Print strQuery & "=" & smimeQuery(strFileIn, strQuery, 0) strQuery = "smime-type" Debug.Print strQuery & "=" & smimeQuery(strFileIn, strQuery, 0) strQuery = "encoding" Debug.Print strQuery & "=" & smimeQuery(strFileIn, strQuery, 0) strQuery = "filename" Debug.Print strQuery & "=" & smimeQuery(strFileIn, strQuery, 0)
Wrap a CMS object in an S/MIME entity.
Public Declare Function SMIME_Wrap Lib "diCrPKI.dll" (ByVal strFileOut As String, ByVal strFileIn As String, ByVal strFeatures As String, ByVal nOptions As Long) As Long
nRet = SMIME_Wrap(strFileOut, strFileIn, strFeatures, nOptions)
long __stdcall SMIME_Wrap(const char *szFileOut, const char *szFileIn, const char *szFeatures, long nOptions);
"" or NULL for defaults.A positive number giving the size of the output file in bytes; or a negative error code.
static int dipki::Smime::Wrap (const std::string &outputFile, const std::string &inputFile, Encoding encoding=Encoding::Default, AdvOpts advopts=AdvOpts::Default)
static Smime.wrap(outputfile, inputfile, opts=0)
This forms an S/MIME entity with a Content-Type of application/pkcs7-mime from a binary CMS object.
It works in file-to-file mode only.
The input file is expected to be a binary CMS object of type enveloped-data, signed-data or compressed-data;
otherwise it is an error.
The type of input file is detected automatically.
The output is a text file with the correct S/MIME headers according to [SMIME-MSG].
By default the body is encoded in base64.
Use the PKI_SMIME_ENCODE_BINARY option to encode the body in "binary" instead.
Use the PKI_SMIME_ADDX option to change the Content-Type to
application/x-pkcs7-mime for compatibility with legacy applications.
S/MIME signed messages with the multipart/signed format are currently not supported.
nRet = SMIME_Wrap("cmsalice2bob-smime-env.txt", "cmsalice2bob.p7m", "", 0)
In this example, the binary file cmsalice2bob.p7m was created using
CMS_MakeEnvData.
The output file should look like the following.
Content-Type: application/pkcs7-mime;
smime-type=enveloped-data;
id="smime.p7m"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
fileid="smime.p7m"
MIAGCSqGSIb3DQEHA6CAMIACAQAxgcAwgb0CAQAwJjASMRAwDgYDVQQDEwdDYXJs
UlNBAhBGNGvHgABWvBHTbi7NXXHQMA0GCSqGSIb3DQEBAQUABIGAFx80IYQbAX8+
7PIXJzUInDUydJv9tgogwzQY8KHwneD1Wcihc/Thi3QtSIQu4bnoPlSbGdF76SuE
Cajdnq5PDU34SnMywq8fyBxDM0ayUfYfMozZOhnM4mr9F4lF3zqtAhnukQF8b+Hv
cTgt4XHHrk2P5vHhdtaA4spSM9kDtpwwgAYJKoZIhvcNAQcBMBQGCCqGSIb3DQMH
BAh7TZ7TVakVU6CABCCNGoP9xsyKSFr1lFrffFky8Ym+efPbS4jx1ODxWzHa3wAA
AAAAAAAAAAA=
Encrypts or decrypts data encoded in base64 using a specified mode. The key and initialization vector are required in base64.
Public Declare Function TDEA_B64Mode Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal strInput As String, ByVal strKey As String,
ByVal fEncrypt As Long, ByVal strMode As String, ByVal strIV As String) As Long
nRet = TDEA_B64Mode(strOutput, strInput, strKey, fEncrypt, strMode, strIV)
long __stdcall TDEA_B64Mode(char *szOutput, const char *szInput, const char *szKey, long fEncrypt, const char *szMode, const char *szIV);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Tdea.Encrypt Method (String, String, Mode, String, EncodingBase)
Tdea.Decrypt Method (String, String, Mode, String, EncodingBase)
For ECB and CBC modes, the input string szInput must represent an exact multiple of eight bytes when decoded
otherwise a "Data not a valid length" error will result.
The key string szKey must represent exactly 24 bytes when decoded.
The initialization vector
string szIV must represent exactly 8 bytes when decoded
unless szMode is ECB,
in which case szIV is ignored (use "").
Valid base64 characters are [A-Za-z0-9+/] with '=' used as a padding character.
The output string szOutput must be set up with at least the same
number of characters as the input string before calling.
The variables szOutput and szInput should be different.
Examples in base64 are pretty obscure to read. This is the same example from
TDEA_HexMode
using base64 strings instead.
Dim nRet As Long Dim sHexCorrect As String Dim sHexInput As String Dim sHexKey As String Dim sHexInitV As String Dim sOutput As String Dim sInput As String Dim sKey As String Dim sInitV As String Dim bEncrypt As Boolean Dim sCorrect As String ' Start with input in hex sHexInput = "5468697320736F6D652073616D706520636F6E74656E742E0808080808080808" ' T h i s _ s o m e _ s a m p e _ c o n t e n t . (padding 8 x 08) sHexKey = "737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32" sHexInitV = "B36B6BFB6231084E" sHexCorrect = "d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4" ' Convert to base64 sInput = cnvB64StrFromBytes(cnvBytesFromHexStr(sHexInput)) sKey = cnvB64StrFromBytes(cnvBytesFromHexStr(sHexKey)) sInitV = cnvB64StrFromBytes(cnvBytesFromHexStr(sHexInitV)) sCorrect = cnvB64StrFromBytes(cnvBytesFromHexStr(sHexCorrect)) ' Set sOutput to be same length as sInput sOutput = String(Len(sInput), " ") Debug.Print "KY=" & sKey Debug.Print "PT=" & sInput Debug.Print "IV=" & sInitV nRet = TDEA_B64Mode(sOutput, sInput, sKey, ENCRYPT, "CBC", sInitV) Debug.Print "CT=" & sOutput & nRet Debug.Print "OK=" & sCorrect sInput = sOutput nRet = TDEA_B64Mode(sOutput, sInput, sKey, DECRYPT, "CBC", sInitV) Debug.Print "P'=" & sOutput & nRet
Encrypts or decrypts an array of Bytes in one step using a specified mode.
Public Declare Function TDEA_BytesMode Lib "diCrPKI.dll"
(ByRef lpOutput As Byte, ByRef lpInput As Byte, ByVal nDataLen As Long, ByRef lpKey As Byte,
ByVal fEncrypt As Long, ByVal strMode As String, ByRef lpIV As Byte) As Long
nRet = TDEA_BytesMode(lpOutput(0), lpInput(0), nDataLen,
lpKey(0), fEncrypt, strMode, lpIV(0)) ' Note the "(0)" after the byte array parameters
long __stdcall TDEA_BytesMode(unsigned char *lpOutput, const unsigned char *lpData, long nDataLen, const unsigned char *lpKey, long fEncrypt, const char *szMode, const unsigned char *lpIV);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Tdea.Encrypt Method (Byte[], Byte[], Mode, Byte[])
Tdea.Decrypt Method (Byte[], Byte[], Mode, Byte[])
For ECB and CBC modes, the input data lpInput must be a multiple of 8 bytes long otherwise a "Data not a valid length" error will result. The key lpKey must be exactly 24 bytes long and the IV, if required, exactly 8 bytes long. The output array lpOutput must be at least nDataLen bytes long. lpOutput and lpInput may be the same.
Dim nRet As Long Dim sOutput As String Dim sInput As String Dim sKey As String Dim sHexIV As String Dim sCorrect As String Dim nKeyLen As Long Dim nDataLen As Long Dim nIVLen As Long Dim aKey() As Byte Dim aResult() As Byte Dim aData() As Byte Dim aInitV() As Byte sKey = "0123456789abcdeffedcba987654321089abcdef01234567" sHexIV = "1234567890abcdef" sInput = "Now is the time for all " sCorrect = "204011f986e35647199e47af391620c5bb9a5bcfc86db0bb" ' Convert hex strings to byte arrays nKeyLen = Len(sKey) \ 2 ReDim aKey(nKeyLen) Call CNV_BytesFromHexStr(aKey(0), nKeyLen, sKey) nIVLen = Len(sHexIV) \ 2 ReDim aInitV(nIVLen) Call CNV_BytesFromHexStr(aInitV(0), nIVLen, sHexIV) ' Convert string to byte array and dimension aResult array aData() = StrConv(sInput, vbFromUnicode) nDataLen = UBound(aData) + 1 ReDim aResult(nDataLen - 1) Debug.Print "KY=" & cnvHexStrFromBytes(aKey) Debug.Print "IV=" & cnvHexStrFromBytes(aInitV) Debug.Print "PT=" & "[" & sInput & "]" ' Encrypt in one-off process nRet = TDEA_BytesMode(aResult(0), aData(0), nDataLen, _ aKey(0), ENCRYPT, "CBC", aInitV(0)) Debug.Print "CT=" & cnvHexStrFromBytes(aResult) & nRet Debug.Print "OK=" & sCorrect ' Now decrypt back nRet = TDEA_BytesMode(aData(0), aResult(0), nDataLen, _ aKey(0), DECRYPT, "cbc", aInitV(0)) sOutput = StrConv(aData(), vbUnicode) Debug.Print "P'=" & "[" & sOutput & "]" & nRet
This should result in output as follows:
KY=0123456789ABCDEFFEDCBA987654321089ABCDEF01234567 IV=1234567890ABCDEF PT=[Now is the time for all ] CT=204011F986E35647199E47AF391620C5BB9A5BCFC86DB0BB 0 OK=204011f986e35647199e47af391620c5bb9a5bcfc86db0bb P'=[Now is the time for all ] 0
TDEA_HexMode TDEA_B64Mode TDEA_File
Encrypts or decrypts a file using a specified mode. The key and initialization vector are passed as arrays of bytes. PKCS-5/7 padding is used.
Public Declare Function TDEA_File Lib "diCrPKI.dll"
(ByVal strFileOut As String, ByVal strFileIn As String, ByRef lpKey As Byte,
ByVal fEncrypt As Long, ByVal strMode As String, ByRef lpInitV As Byte) As Long
nRet = TDEA_File(strFileOut, strFileIn, lpKey(0), fEncrypt, strMode, lpInitV(0))
long __stdcall TDEA_File(const char *szFileOut, const char *szFileIn, const unsigned char *lpKey, long fEncrypt, const char *szMode, const unsigned char *lpIV);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Tdea.FileEncrypt Method (String, String, Byte[], Mode, Byte[])
Tdea.FileDecrypt Method (String, String, Byte[], Mode, Byte[])
The key array abKey()
must be exactly 16 bytes long.
The initialization vector abInitV()
must be exactly the block size of 16 bytes long, except for ECB mode, where it is ignored (use 0).
The output file szFileOut will be overwritten without warning.
If there is an error, the output file will not exist.
The input and output files must not be the same.
In ECB and CBC modes, a padding string will be added or assumed according to the method outlined in Section 6.3 of
[CMS],
which is the same as the padding method in [PKCS7] section 10.3 and [PKCS5] section 6.1.1
and [RFC1423] para 1.1.
Const MY_PATH As String = ""
Dim aKey() As Byte
Dim strFileOut As String
Dim strFileIn As String
Dim strFileChk As String
Dim nRet As Long
' Construct full path names to files
strFileIn = MY_PATH & "hello.txt"
strFileOut = MY_PATH & "hello.tdea.enc.dat"
strFileChk = MY_PATH & "hello.tdea.chk.txt"
' Create the key as an array of bytes
' This creates an array of 24 bytes {&HFE, &HDC, ... &H10}
aKey = cnvBytesFromHexStr("fedcba9876543210fedcba9876543210fedcba9876543210")
' Encrypt plaintext file to ciphertext
' Output file = 16-byte ciphertext file hello.enc
nRet = TDEA_File(strFileOut, strFileIn, aKey(0), ENCRYPT, "ECB", 0)
Debug.Print nRet
' Now decrypt it
nRet = TDEA_File(strFileChk, strFileOut, aKey(0), DECRYPT, "ECB", 0)
Debug.Print nRet
Encrypts or decrypts data represented as a hexadecimal string using a specified mode. The key and initialization vector are represented as a hexadecimal string.
Public Declare Function TDEA_HexMode Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal strInput As String, ByVal strKey As String,
ByVal fEncrypt As Long, ByVal strMode As String, ByVal strIV As String) As Long
nRet = TDEA_HexMode(strOutput, strInput, strKey, fEncrypt, strMode, strIV)
long __stdcall TDEA_HexMode(char *szOutput, const char *szInput, const char *szKey, long fEncrypt, const char *szMode, const char *szIV);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Tdea.Encrypt Method (String, String, Mode, String)
Tdea.Decrypt Method (String, String, Mode, String)
For ECB and CBC modes, the length of the input string szInput must be a multiple of 16 hex characters long
(i.e. representing a multiple of 8 bytes) otherwise an error will result.
The key string szKey
must be exactly 48 hex characters long (i.e. representing exactly 24 bytes/192 bits).
The initialization vector
string szIV must be exactly 16 hex characters long
(i.e. representing exactly the block size of 8 bytes) unless szMode is ECB,
in which case szIV is ignored (use "").
Valid hexadecimal characters are [0-9A-Fa-f].
The output string szOutput must be set up with the same
number of characters as the input string before calling.
The variables szOutput and szInput should be different.
This example is from Section 8.1 of [SMIME-EX].
Dim nRet As Long Dim sOutput As String Dim sInput As String Dim sKey As String Dim sInitV As String Dim sCorrect As String sInput = "5468697320736F6D652073616D706520636F6E74656E742E0808080808080808" ' T h i s _ s o m e _ s a m p e _ c o n t e n t . (padding 8 x 08) sKey = "737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32" sInitV = "B36B6BFB6231084E" sCorrect = "d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4" ' Set sOutput to be same length as sInput sOutput = String(Len(sInput), " ") Debug.Print "KY=" & sKey Debug.Print "PT=" & sInput nRet = TDEA_HexMode(sOutput, sInput, sKey, ENCRYPT, "CBC", sInitV) Debug.Print "CT=" & sOutput & nRet Debug.Print "OK=" & sCorrect sInput = sOutput nRet = TDEA_HexMode(sOutput, sInput, sKey, DECRYPT, "CBC", sInitV) Debug.Print "P'=" & sOutput & nRet
This should result in output as follows:
KY=737C791F25EAD0E04629254352F7DC6291E5CB26917ADA32 PT=5468697320736F6D652073616D706520636F6E74656E742E0808080808080808 CT=D76FD1178FBD02F84231F5C1D2A2F74A4159482964F675248254223DAF9AF8E4 0 OK=d76fd1178fbd02f84231f5c1d2a2f74a4159482964f675248254223daf9af8e4 P'=5468697320736F6D652073616D706520636F6E74656E742E0808080808080808 0
Zeroise data in memory.
Public Declare Function WIPE_Data Lib "diCrPKI.dll"
(ByRef lpData As Byte, ByVal nBytes As Long) As Long
Alternative aliases for VBA/VB6 users to deal with Byte and String types explicitly:
Public Declare Function WIPE_Bytes Lib "diCrPKI.dll" Alias "WIPE_Data"
(ByRef lpData As Byte, ByVal nBytes As Long) As Long
Public Declare Function WIPE_String Lib "diCrPKI.dll" Alias "WIPE_Data"
(ByVal strData As String, ByVal nStrLen As Long) As Long
nRet = WIPE_Data(lpData(0), nBytes) ' Note the "(0)" after the byte array parameters
VBA/VB6 aliases only:
nRet = WIPE_Bytes(lpData(0), nBytes)
nRet = WIPE_String(strData, nStrLen)
long __stdcall WIPE_Data(void *lpData, long nDataLen);
If successful, the return value is zero; otherwise it returns a nonzero error code.
Public Function wipeBytes (ByRef lpToWipe() As Byte) As Byte()
Public Function wipeString (ByRef szToWipe As String) As String
Wipe.Data Method
Wipe.String Method
static bool dipki::Wipe::Data (bvec_t &data)
static bool dipki::Wipe::String (std::string &s)
static Wipe.data(data)
This function does not free any memory; it just zeroises it.
Dim lpData() As Byte
lpData = ... ' n bytes of data
nRet = WIPE_Data(lpData(0), n)
Dim strData As String
strData = "my deepest secrets"
nRet = WIPE_String(strData, Len(strData))
strData = ""
long pwdlen;
char password[256];
pwdlen = PWD_Prompt(password, sizeof(password)-1, "Test");
if (pwdlen >= 0)
printf("Password entered=[%s]\n", password);
else
printf("No password entered\n");
/* ... do something with password ... */
WIPE_Data(password, pwdlen);
Dim strData As String
strData = "my deepest secrets"
strData = wipeString(strData)
Dim lpData() As Byte
lpData = cnvBytesFromHexStr("DEADBEEF")
Debug.Print "BEFORE: " & cnvHexStrFromBytes(lpData)
Call wipeBytes(lpData)
Debug.Print "AFTER: '" & cnvHexStrFromBytes(lpData) & "'"
Wipe and delete a file using secure 7-pass DOD standards.
Public Declare Function WIPE_File Lib "diCrPKI.dll"
(ByVal strFileName As String, ByVal nOptions As Long) As Long
nRet = WIPE_File(strFileName, nOptions)
long __stdcall WIPE_File(const char *szFileName, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
static bool dipki::Wipe::File (const std::string fileName, Opts opts=Opts::Dod7Pass)
static Wipe.file(filename, opts=Options.DEFAULT)
Wipes a file using the 7-pass DOD Standard according to [NISPOM] before deleting.
nRet = WIPE_File("ToDelete.txt", 0)
Returns the date and time an X.509 certificate expires.
Public Declare Function X509_CertExpiresOn Lib "diCrPKI.dll"
(ByVal strCertFile As String, ByVal strOutput As String,
ByVal nOutChars As Long, ByVal nOptions As Long) As Long
nRet = X509_CertExpiresOn(strCertFile, strOutput, nOutChars, nOptions)
long __stdcall X509_CertExpiresOn(const char *szCertFile, char *szOutput, long nOutChars, long nOptions);
Returns the number of characters set in szOutput. If nOutChars is zero it returns the maximum number of characters required (currently 20, but don't assume that for future releases). C/C++ users should allocate one extra for the terminating NUL character. If an error occurs, it returns a negative error code.
The time format is in accordance with ISO 8601 and will always be of the form YYYY-MM-DDThh:mm:ssZ. The time is always given as GMT (Greenwich Mean Time, UTC, Zulu Time).
Dim nRet As Long Dim strCertName As String Dim strDateTime As String * 32 strCertName = "AliceRSASignByCarl.cer" ' Change your dir to suit nRet = X509_CertIssuedOn(strCertName, strDateTime, Len(strDateTime), 0) Debug.Print "X509_CertIssuedOn returns " & nRet & " for " & strCertName & ": " & strDateTime nRet = X509_CertExpiresOn(strCertName, strDateTime, Len(strDateTime), 0) Debug.Print "X509_CertExpiresOn returns " & nRet & " for " & strCertName & ": " & strDateTime
Should result in (in all locales):
X509_CertIssuedOn returns 20 for AliceRSASignByCarl.cer: 1999-09-19T01:08:47Z X509_CertExpiresOn returns 20 for AliceRSASignByCarl.cer: 2039-12-31T23:59:59Z
X509_CertIssuedOn X509_CertIsValidNow X509_QueryCert
Returns the date and time an X.509 certificate was issued.
Public Declare Function X509_CertIssuedOn Lib "diCrPKI.dll"
(ByVal strCertFile As String, ByVal strOutput As String,
ByVal nOutChars As Long, ByVal nOptions As Long) As Long
nRet = X509_CertIssuedOn(strCertFile, strOutput, nOutChars, nOptions)
long __stdcall X509_CertIssuedOn(const char *szCertFile, char *szOutput, long nOutChars, long nOptions);
Returns the number of characters set in szOutput. If nOutChars is zero it returns the maximum number of characters required (currently 20, but don't assume that for future releases). C/C++ users should allocate one extra for the terminating NUL character. If an error occurs, it returns a negative error code.
The time format is in accordance with ISO 8601 and will always be of the form YYYY-MM-DDThh:mm:ssZ. The time is always given as GMT (Greenwich Mean Time, UTC, Zulu Time).
See X509_CertExpiresOn.
X509_CertExpiresOn X509_CertIsValidNow X509_QueryCert
Extracts issuer's distinguished name from X.509 certificate.
Public Declare Function X509_CertIssuerName Lib "diCrPKI.dll"
(ByVal strCertFile As String, ByVal strOutput As String,
ByVal nOutChars As Long, ByVal strDelim As String, ByVal nOptions As Long) As Long
nRet = X509_CertIssuerName(strCertFile, strOutput, nOutChars, strDelim, nOptions)
long __stdcall X509_CertIssuerName(const char *szCertFile, char *szOutput, long nOutChars, const char *szDelim, long nOptions);
Returns the number of characters set in szOutput. If nOutChars is zero it returns the maximum number of characters required. C/C++ users should allocate one extra for the terminating NUL character. If an error occurs, it returns a negative error code.
The output using the PKI_X509_LDAP option is suitable as content for an <X509IssuerName>
node in an XML-DSIG document.
See the remarks for X509_CertSubjectName().
See X509_CertSubjectName.
X509_CertIssuerName X509_HashIssuerAndSN X509_QueryCert
Verifies that an X.509 certificate is currently valid.
Public Declare Function X509_CertIsValidNow Lib "diCrPKI.dll"
(ByVal strCertFile As String, ByVal nOptions As Long) As Long
nRet = X509_CertIsValidNow(strCertFile, nOptions)
long __stdcall X509_CertIsValidNow(const char *szCertFile, long nOptions);
Zero (0) if the certificate is valid at the current time.
If the certificate has expired or is not yet valid, the return value is
PKI_X509_EXPIRED (+16 = EXPIRED_ERROR);
otherwise it returns a positive error code.
static bool dipki::X509::CertIsValidNow (const std::string &certFile)
static X509.cert_is_valid_now(certfile)
Note that the return value for "success" is zero, not "true". Uses the system clock. The certificate may be in binary DER format or base64 PEM format.
[Changed in v12.0] If the certificate is otherwise of correct format but has expired or is not yet valid, this function returns EXPIRED_ERROR (16). Previous versions would return -1.
Dim nRet As Long Dim strCertName As String strCertName = "myca.cer" nRet = X509_CertIsValidNow(strCertName, 0) Debug.Print "X509_CertIsValidNow returns " & nRet & " for " & strCertName
X509_VerifyCert X509_ValidatePath X509_CertThumb
Creates a PKCS #10 certificate signing request (CSR) using the subject's private key file.
Public Declare Function X509_CertRequest Lib "diCrPKI.dll"
(ByVal strReqFile As String, ByVal strPriKeyFile As String,
ByVal strDistName As String, ByVal strExtensions As String,
ByVal strPassword As String, ByVal nOptions As Long) As Long
nRet = X509_CertRequest(strReqFile,
strPriKeyFile, strDistName, strExtensions, strPassword, nOptions)
long __stdcall X509_CertRequest(const char *szNewReqFile, const char *szPriKeyFile, const char *szDistName, const char *szExtensions, const char *szPassword, long nOptions);
extensionRequest element.
See X.509 Extensions Parameter.
[New in v10.0].
"" if key not encrypted [New in v12.0].sha1WithRSAEncryption (default - CAUTION)sha224WithRSAEncryptionsha256WithRSAEncryption [minimum recommended]sha384WithRSAEncryptionsha512WithRSAEncryptionmd5WithRSAEncryption [legacy, not recommended]md2WithRSAEncryption [legacy, definitely not recommended]RSA-PSS-SHA1RSA-PSS-SHA224RSA-PSS-SHA256RSA-PSS-SHA384RSA-PSS-SHA512ecdsaWithSHA1ecdsaWithSHA224ecdsaWithSHA256ecdsaWithSHA384ecdsaWithSHA512Ed25519 [New in v20.0]Ed448 [New in v22.0]UTF8String (default = PrintableString)If successful, the return value is zero; otherwise it returns a nonzero error code.
static int dipki::X509::CertRequest (const std::string &newFile, const std::string &priKeyFile, const std::string &password, const std::string distName, const std::string extns="", SigAlg sigAlg=SigAlg::Default, CsrOptions opts=CsrOptions::Default_CsrOpt)
static X509.cert_request(newcsrfile, prikeyfile, password, distname, extns="", sigalg=0, opts=0)
The default output is a base64 PEM format CSR file ready for sending to the issuer of your choice. Any existing file of the same name will be overwritten without warning.
This example will create a new certificate request with filename myreq.p10.txt.
for the subject with common name "myuser", etc.
The subject's encrypted private key is in the file mykey.p8e and has
the password "password". The certificate request will be signed using the subject's private key
using the default sha1WithRSAEncryption algorithm.
Dim nRet As Long
nRet = X509_CertRequest("myreq.p10.txt", "mykey.p8e", _
"CN=myuser;O=Test Org;C=AU;L=Sydney;S=NSW", "", "password", 0)
If nRet <> 0 Then
Debug.Print nRet & " " & pkiGetLastError()
Else
Debug.Print "Success"
End If
This should produce an output file similar to:
-----BEGIN CERTIFICATE REQUEST----- MIIBGjCBxQIBADBQMQ8wDQYDVQQDEwZteXVzZXIxETAPBgNVBAoTCFRlc3QgT3Jn MQswCQYDVQQGEwJBVTEPMA0GA1UECBMGU3lkbmV5MQwwCgYDVQQHEwNOU1cwWjAN BgkqhkiG9w0BAQEFAANJADBGAkEAvdci5sKarpPzljBVVxJfGEfBOvjxlgFYOg1x xEEG9Xbilxgl3kTfIrA4KqNmGdEKPksbHXNuxXkwaaAld3bBHQIBA6ASMBAGCisG AQQBgjcCAQ4xAjAAMA0GCSqGSIb3DQEBBQUAA0EAtqie6G31yRcwJljEDdbeYd+w 5FvLd631nL//JuISFv6fl9B30WtHQtI1wuryVYZ6fRWZPpu9jZjs5gsnKFtiUg== -----END CERTIFICATE REQUEST-----
The next example duplicates the certificate request in Sections 3.1 to 3.3 of "Some Examples of the PKCS Standards"
[PKCS-EX].
It uses the 508-bit private key to sign the request, which is stored in the file rsa508.p8e
with the password "password". The signature algorithm is md2WithRSAEncryption
and the output is in binary format. To reproduce this example requires the non-strict "kludge".
The output should exactly match the CertificationRequest value in section 3.2 of PKCS-EX.
Dim nRet As Long
nRet = X509_CertRequest("pkcs_ex_req.bin", "rsa508.p8e", _
"C=US;O=Example Organization;CN=Test User 1", "", "password", _
PKI_SIG_MD2RSA + PKI_X509_FORMAT_BIN + PKI_X509_REQ_KLUDGE)
If nRet <> 0 Then
Debug.Print nRet & " " & pkiGetLastError()
Else
Debug.Print "Success"
End If
The latter example is just to demonstrate the replication of an old but known test vector, not to demonstrate good practice.
Returns the serial number of an X.509 certificate.
Public Declare Function X509_CertSerialNumber Lib "diCrPKI.dll"
(ByVal strCertFile As String, ByVal strOutput As String,
ByVal nOutChars As Long, ByVal nOptions As Long) As Long
nRet = X509_CertSerialNumber(strCertFile, strOutput, nOutChars, nOptions)
long __stdcall X509_CertSerialNumber(const char *szCertFile, char *szOutput, long nOutChars, long nOptions);
Returns the number of characters set in szOutput. If nOutChars is zero it returns the maximum number of characters required. C/C++ users should allocate one extra for the terminating NUL character. If an error occurs, it returns a negative error code.
The certificate may be in binary DER format or base64 PEM format.
Dim nRet As Long Dim strCertName As String Dim strOutput As String * 64 strCertName = "BobRSASignByCarl.cer" ' Set dir to suit nRet = X509_CertSerialNumber(strCertName, strOutput, Len(strOutput), 0) Debug.Print "X509_CertSerialNumber returns " & nRet & " for " & strCertName & ": " & Left(strOutput, nRet)
Should result in
X509_CertSerialNumber returns 32 for BobRSASignByCarl.cer: 46346bc7800056bc11d36e2ecd5d71d0
X509_CertIsValidNow X509_CertThumb
Extracts subject's distinguished name from X.509 certificate.
Public Declare Function X509_CertSubjectName Lib "diCrPKI.dll"
(ByVal strCertFile As String, ByVal strOutput As String,
ByVal nOutChars As Long, ByVal strDelim As String, ByVal nOptions As Long) As Long
nRet = X509_CertSubjectName(strCertFile, strOutput, nOutChars, strDelim, nOptions)
long __stdcall X509_CertSubjectName(const char *szCertFile, char *szOutput, long nOutChars, const char *szDelim, long nOptions);
Returns the number of characters set in szOutput. If nOutChars is zero it returns the maximum number of characters required. C/C++ users should allocate one extra for the terminating NUL character. If an error occurs, it returns a negative error code.
The distinguished name will be returned in a string expressed
in the same format described in Distinguished Names, e.g. "C=AU;O=myorg;CN=Dave".
Only the first character in szDelim is used.
The default delimiter is a semi-colon (;) if an empty string or NULL is specified for szDelim.
If the attribute key is not in our set of supported types,
the OID will be expressed in dot notation, e.g. "2.5.4.4=My Surname".
If an attribute value is encoded in a multi-byte-character string format (such as UTF8String or BMPString),
the value will be expressed as a hexadecimal-encoded string [NB changed in v3.9]
preceded by the hash symbol ('#' U+0023) and small letter x ('x' U+0078), e.g.
"C=TW;O=E8 A1 8C E6 94 BF E9 99 A2" (v3.8 and earlier)
"C=TW;O=#xE8A18CE694BFE999A2" (v3.9 and later)
Use the PKI_X509_LATIN1 option to return the string encoded in Latin-1, if possible, so it will display properly on systems that cannot cope with UTF-8.
[New in v3.9] Use the PKI_X509_LDAP option to obtain the distinguished name in LDAP string form instead.
The examples above would be returned as "CN=Dave,O=myorg,C=AU" and
"O=\E8\A1\8C\E6\94\BF\E9\99\A2,C=TW", with commas as delimiters, the RDNs in reverse order, and non-printable-ASCII
characters escaped in hexadecimal form "\xx" as per [RFC4514].
See LDAP string representation for more details.
The szDelim parameter is ignored with the PKI_X509_LDAP option.
The output using the PKI_X509_LDAP option is suitable as content for an <X509SubjectName>
node in an XML-DSIG document.
Dim nRet As Long Dim nLen As Long Dim strCertName As String Dim strOutput As String strCertName = "dai.cer" nLen = X509_CertIssuerName(strCertName, "", 0, ";", 0) Debug.Print "X509_CertIssuerName returns " & nLen & " for " & strCertName strOutput = String(nLen, " ") nRet = X509_CertIssuerName(strCertName, strOutput, Len(strOutput), ";", 0) Debug.Print "[" & strOutput & "]" ' Example outputting in LDAP format nLen = X509_CertIssuerName(strCertName, "", 0, "", PKI_X509_LDAP) Debug.Print "X509_CertIssuerName(LDAP) returns " & nLen & " for " & strCertName strOutput = String(nLen, " ") nRet = X509_CertIssuerName(strCertName, strOutput, Len(strOutput), "", PKI_X509_LDAP) Debug.Print "[" & strOutput & "]" nLen = X509_CertSubjectName(strCertName, "", 0, ";", 0) Debug.Print "X509_CertSubjectName returns " & nLen & " for " & strCertName strOutput = String(nLen, " ") nRet = X509_CertSubjectName(strCertName, strOutput, Len(strOutput), ",", 0) Debug.Print "[" & strOutput & "]" ' Example outputting in LDAP format nLen = X509_CertSubjectName(strCertName, "", 0, "", PKI_X509_LDAP) Debug.Print "X509_CertSubjectName(LDAP) returns " & nLen & " for " & strCertName strOutput = String(nLen, " ") nRet = X509_CertSubjectName(strCertName, strOutput, Len(strOutput), "", PKI_X509_LDAP) Debug.Print "[" & strOutput & "]"
This example is for an old Thawte personal certificate. The output is as follows:
X509_CertIssuerName returns 100 for dai.cer [C=ZA;ST=Western Cape;L=Cape Town;O=Thawte;OU=Certificate Services;CN=Personal Freemail RSA 2000.8.30] X509_CertIssuerName(LDAP) returns 100 for dai.cer [CN=Personal Freemail RSA 2000.8.30,OU=Certificate Services,O=Thawte,L=Cape Town,ST=Western Cape,C=ZA] X509_CertSubjectName returns 76 for dai.cer [SN=Ireland,G=David Alexander,CN=David Alexander Ireland,E=code@di-mgt.com.au] X509_CertSubjectName(LDAP) returns 107 for dai.cer [1.2.840.113549.1.9.1=code@di-mgt.com.au,CN=David Alexander Ireland,2.5.4.42=David Alexander,2.5.4.4=Ireland]
X509_CertIssuerName X509_HashIssuerAndSN X509_QueryCert
Calculates the thumbprint (message digest hash) of an X.509 certificate.
Public Declare Function X509_CertThumb Lib "diCrPKI.dll"
(ByVal strCertFile As String, ByVal strHexHash As String,
ByVal nHexHashLen As Long, ByVal nOptions As Long) As Long
nRet = X509_CertThumb(strCertFile,
strHexHash, nHexHashLen, nOptions)
long __stdcall X509_CertThumb(const char *szCertFile, char *szOutput, long nOutChars, long nOptions);
the number of digits set in the output string or a negative error code.
Public Function x509CertThumb (szCertFile As String, Optional nOptions As Long = 0) As String
static std::string dipki::X509::CertThumb (const std::string &certFile, HashAlg hashAlg=HashAlg::Sha1)
static X509.cert_thumb(certfilename, hashalg=0)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The maximum length of the output string is PKI_MAX_HASH_CHARS (C/C++ users add one).
The default hash algorithm is SHA-1 and the result should
match the SHA-1 thumbprint shown in the Windows Certificate Viewer.
These examples compute the SHA-1 message digest hash ("thumbprint") of Alice's certificate from S/MIME examples.
Dim nRet As Long Dim strCertName As String Dim strHexHash As String strHexHash = String(PKI_SHA1_CHARS, " ") strCertName = "AliceRSASignByCarl.cer" nRet = X509_CertThumb(strCertName, strHexHash, Len(strHexHash), 0) Debug.Print "X509_CertThumb returns " & nRet & " for " & strCertName Debug.Print strHexHash
In C:
long lRet;
char *certname = "C:\\test\\AliceRSASignByCarl.cer";
char hexdigest[PKI_SHA1_CHARS+1]; /* NB one extra */
lRet = X509_CertThumb(certname, hexdigest, sizeof(hexdigest)-1, 0);
printf("X509_CertThumb returns %ld for %s\n", lRet, certname);
printf("%s\n", hexdigest);
Both of these should result in
X509_CertThumb returns 40 for AliceRSASignByCarl.cer b30c48855055c2e64ce3196492d4b83831a6b3cb
Dim strCertString As String
strCertString = x509ReadStringFromFile("AliceRSASignByCarl.cer")
Debug.Print strCertString
Debug.Print "CertThumb=" & x509CertThumb(strCertString)
strCertString = x509ReadCertStringFromP7Chain("alice_bob_carl_certs.p7c", 3)
Debug.Print strCertString
Debug.Print "CertThumb=" & x509CertThumb(strCertString)
Debug.Print "HashIssuerAndSN=" & x509HashIssuerAndSN(strCertString, PKI_HASH_SHA256)
X509_CertIsValidNow X509_VerifyCert
Checks whether an X.509 certificate has been revoked in a Certificate Revocation List (CRL).
Public Declare Function X509_CheckCertInCRL Lib "diCrPKI.dll" (ByVal strCertFile As String, ByVal strCrlFile As String, ByVal strCRLIssuerCert As String, ByVal strDate As String, ByVal nOptions As Long) As Long
nRet = X509_CheckCertInCRL(strCertFile, strCrlFile, strCRLIssuerCert,
strDate, nOptions)
long __stdcall X509_CheckCertInCRL(const char *szCertFile, const char *szCrlFile, const char *szCRLIssuerCert, const char *szDate, long nOptions);
2009-12-31T12:59:59Z)
on or after you wish to check for revocation.
Leave empty "" for any date. The time must be in GMT (UTC, Zulu time).
Zero (0) if the certificate is not in the CRL (i.e has not been revoked by that particular CRL).
If the certificate has been revoked it returns PKI_X509_REVOKED (+42=REVOCATION_ERROR);
otherwise a negative error code.
static X509.cert_is_revoked(certfile, crlfile, crl_issuercert="", isodate="")
The optional szDate parameter allows you to check whether a certificate was revoked only after the given date-time,
which must be in GMT (UTC). If the optional szCRLIssuerCert is specified,
the signature of the CRL will be checked against the key in the issuer's certificate and a SIGNATURE_ERROR will result
if the signature is invalid.
You can directly verify the signature in the CRL file using the X509_VerifyCert() function.
[Changed in v12.0] If the certificate is otherwise of correct format but has been revoked, this function returns REVOCATION_ERROR (42). Previous versions would return +1.
Dim nRet As Long Dim strCrlFile As String Dim strCertFile As String Dim strDate As String ' Use test CRL and certs from RFC3280 strCrlFile = "rfc3280bis_CRL.crl" ' This cert has not been revoked. strCertFile = "rfc3280bis_cert1.cer" Debug.Print "CrlFile=" & strCrlFile Debug.Print "CertFile=" & strCertFile nRet = X509_CheckCertInCRL(strCertFile, strCrlFile, "", "", 0) Debug.Print "X509_CheckCertInCRL returns " & nRet If nRet = PKI_X509_REVOKED Then Debug.Print "CERT HAS BEEN REVOKED" ElseIf nRet = 0 Then Debug.Print "Cert has not been revoked" Else Debug.Print "ERROR: " & pkiErrorLookup(nRet) & ": " & pkiGetLastError() End If ' This cert has been revoked. strCertFile = "rfc3280bis_cert2.cer" Debug.Print "CrlFile=" & strCrlFile Debug.Print "CertFile=" & strCertFile nRet = X509_CheckCertInCRL(strCertFile, strCrlFile, "", "", 0) Debug.Print "X509_CheckCertInCRL returns " & nRet If nRet = PKI_X509_REVOKED Then Debug.Print "CERT HAS BEEN REVOKED" ElseIf nRet = 0 Then Debug.Print "Cert has not been revoked" Else Debug.Print "ERROR: " & pkiErrorLookup(nRet) & ": " & pkiGetLastError() End If ' But the same cert was not revoked as at 15:00 GMT on 19 November 2004 strCertFile = "rfc3280bis_cert2.cer" strDate = "2004-11-19T15:00Z" Debug.Print "CrlFile=" & strCrlFile Debug.Print "CertFile=" & strCertFile Debug.Print "Date=" & strDate nRet = X509_CheckCertInCRL(strCertFile, strCrlFile, "", strDate, 0) Debug.Print "X509_CheckCertInCRL(" & strDate & ") returns " & nRet If nRet = PKI_X509_REVOKED Then Debug.Print "CERT HAS BEEN REVOKED" ElseIf nRet = 0 Then Debug.Print "Cert has not been revoked" Else Debug.Print "ERROR: " & pkiErrorLookup(nRet) & ": " & pkiGetLastError() End If
This code should produce the following output
CrlFile=rfc3280bis_CRL.crl CertFile=rfc3280bis_cert1.cer X509_CheckCertInCRL returns 0 Cert has not been revoked CrlFile=rfc3280bis_CRL.crl CertFile=rfc3280bis_cert2.cer X509_CheckCertInCRL returns 1 CERT HAS BEEN REVOKED CrlFile=rfc3280bis_CRL.crl CertFile=rfc3280bis_cert2.cer Date=2004-11-19T15:00Z X509_CheckCertInCRL(2004-11-19T15:00Z) returns 0 Cert has not been revoked
X509_MakeCRL X509_VerifyCert X509_CertIsValidNow X509_ValidatePath
Return number of certificates in a PKCS-7 "certs-only" certificate chain file.
Public Declare Function X509_GetCertCountInP7Chain Lib "diCrPKI.dll" (ByVal strP7cFile As String, ByVal nOptions As Long) As Long
nRet = X509_GetCertCountInP7Chain(strP7cFile, nOptions) As Long
long __stdcall X509_GetCertCountInP7Chain(const char *szP7cFile, long nOptions);
Number of X.509 certificates found or a negative error code.
X509.GetCertCountInP7Chain Method
static int dipki::X509::GetCertCountInP7Chain (const std::string &inputFile)
static X509.get_cert_count_from_p7(p7file)
This function will also work with CMS signed data objects, too.
nCerts = X509_GetCertCountInP7Chain("certs.p7c", 0)
will return the number of certificates found in the file certs.p7c.
X509_GetCertFromP7Chain X509_ReadCertStringFromP7Chain CMS_QuerySigData
Extracts an X.509 certificate from a PKCS-7 "certs-only" certificate chain file
(typically saved with extension .p7c or .p7b),
saving the output directly as a new file.
Public Declare Function X509_GetCertFromP7Chain Lib "diCrPKI.dll"
(ByVal strOutputFile As String, ByVal strP7cFile As String, ByVal nIndex As Long, ByVal nOptions As Long) As Long
nRet = X509_GetCertFromP7Chain(strOutputFile, strP7cFile, nIndex, nOptions) As Long
long __stdcall X509_GetCertFromP7Chain(const char *szNewCertFile, const char *szP7cFile, long nIndex, long nOptions);
If successful and nIndex 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. If an error occurred, it returns a negative error code.
X509.GetCertFromP7Chain Method
static bool dipki::X509::GetCertFromP7Chain (const std::string &outputFile, const std::string &inputFile, int index)
static X509.get_cert_from_p7(outfile, p7file, index=1)
If nIndex is specified as a number greater than zero, the nIndex'th certificate found in the list, if any, will be extracted and saved directly as a DER-encoded X.509 certificate file. This function will also extract certificates from CMS signed data objects, too.
[New in v12.2] To find the number of certificates in the chain, use X509_GetCertCountInP7Chain. The old (deprecated) way to find the count of certificates was to set nIndex to zero.
nBytes = X509_GetCertFromP7Chain("cert2.cer", "certs.p7c", 2, 0)
will extract the second certificate in certs.p7c
and create a new X.509 certificate file called cert2.cer
containing nBytes bytes.
The following example shows how to extract all the certificates from a PKCS-7 CertList file
Dim nRet As Long Dim strListFile As String Dim strCertFile As String Dim nCerts As Long Dim iCert As Long strListFile = "bob.p7b" ' How many certificates? - NB new function in [v12.2] nCerts = X509_GetCertCountInP7Chain(strListFile, 0) Debug.Print "X509_GetCertCountInP7Chain returns " & nCerts & " for " & strListFile ' Enumerate through them all If nCerts > 0 Then For iCert = 1 To nCerts strCertFile = "bobcert" & iCert & ".cer" nRet = X509_GetCertFromP7Chain(strCertFile, strListFile, iCert, 0) Debug.Print "X509_GetCertFromP7Chain(" & iCert & ") returns " _ & nRet & "->" & strCertFile Next End If
This should result in output as follows:
X509_GetCertCountInP7Chain() returns 2 for bob.p7b X509_GetCertFromP7Chain(1) returns 555->bobcert1.cer X509_GetCertFromP7Chain(2) returns 495->bobcert2.cer
where, in this example, the file bob.p7b contains two X.509 certificates
of size 555 and 495 bytes respectively.
X509_ReadCertStringFromP7Chain X509_GetCertCountInP7Chain CMS_QuerySigData
Extracts an X.509 certificate from a PKCS-12 PFX/.p12 file, saving the output directly as a new file.
Public Declare Function X509_GetCertFromPFX Lib "diCrPKI.dll"
(ByVal strOutputFile As String, ByVal strPfxFile As String,
ByVal strPassword As String, ByVal nOptions As Long) As Long
nRet = X509_GetCertFromPFX(strOutputFile, strPfxFile,
strPassword, nOptions) As Long
long __stdcall X509_GetCertFromPFX(const char *szNewCertFile, const char *szPfxFile, const char *szPassword, long nOptions);
"" if certificate is not encrypted.p7b or .p7c).If successful, it returns the number of bytes written to the output file; otherwise it returns a negative error code.
X509.GetCertFromPFX Method
X509.GetP7ChainFromPFX Method
static bool dipki::X509::GetCertFromPFX (const std::string &outputFile, const std::string &inputFile, const std::string &password)
static X509.get_p7chain_from_pfx(outfile, pfxfile, password)
static X509.get_cert_from_pfx(outfile, pfxfile, password)
static X509.get_p7chain_from_pfx(outfile, pfxfile, password)
The default behaviour is to extract one certificate from the PFX file and save directly
as a DER-encoded X.509 certificate file.
Any existing file of the same name will be overwritten without warning.
It will attempt to find a matching certificate for any private key, otherwise it will save
the first pkcs-12-certBag found in the PFX file containing a
x509Certificate.
Both unencrypted certificates and certificates encrypted with the weak 40-bit encryption used by "default"
in Microsoft and OpenSSL PKCS-12 files are supported, but not any other encryption algorithm.
If no certificate can be found the function will return a negative NO_DATA_ERROR error code.
The PKI_PFX_P7CHAIN option will output all X.509 certificates found into a single PKCS#7 certificate chain file.
The correct MIME-designated file extension for such a file is .p7c, but for historical reasons
Microsoft use .p7b instead.
nChars = X509_GetCertFromPFX("mycert.cer", "mypkcs12file.pfx", "password", 0)
will extract an X.509 certificate from the PKCS-12 file mypkcs12file.pfx
with password "password",
and save it as the new DER-encoded certificate file mycert.cer.
The variable nChars will contain the size in bytes of the new file it created,
or a negative error code.
X509_ReadCertStringFromPFX PFX_VerifySig
Returns the message digest hash of the PKCS #7 issuerAndSerialNumber value of an X.509 certificate in hexadecimal format.
Public Declare Function X509_HashIssuerAndSN Lib "diCrPKI.dll"
(ByVal strCertFile As String, ByVal strOutput As String,
ByVal nOutChars As Long, ByVal nOptions As Long) As Long
nRet = X509_HashIssuerAndSN(strCertFile, strOutput, nOutChars, nOptions)
long __stdcall X509_HashIssuerAndSN(const char *szCertFile, char *szOutput, long nOutChars, long nOptions);
Returns the number of characters set in szOutput. If nOutChars is zero it returns the maximum number of characters required. C/C++ users should allocate one extra for the terminating NUL character. If an error occurs, it returns a negative error code.
Public Function x509HashIssuerAndSN (szCertFile As String, Optional nOptions As Long = 0) As String
static std::string dipki::X509::HashIssuerAndSN (const std::string &certFile, HashAlg hashAlg=HashAlg::Sha1)
static X509.cert_hashissuersn(certfilename, hashalg=0)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The certificate may be in binary BER format or base64 PEM format.
Dim nRet As Long
Dim strCertName As String
Dim strOutput As String * PKI_MAX_HASH_CHARS
strCertName = "BobRSASignByCarl.cer" ' Set dir to suit
nRet = X509_HashIssuerAndSN(strCertName, strOutput, Len(strOutput), 0)
Debug.Print "X509_HashIssuerAndSN returns " & nRet & " for " & strCertName & ": " & Left(strOutput, nRet)
Should result in
X509_HashIssuerAndSN returns 40 for BobRSASignByCarl.cer: 483538bca32adeb3134fe9f74d1ae74cc9ed2e9e
Dim strCertString As String
strCertString = x509ReadStringFromFile("AliceRSASignByCarl.cer")
Debug.Print strCertString
Debug.Print "CertThumb=" & x509CertThumb(strCertString)
strCertString = x509ReadCertStringFromP7Chain("alice_bob_carl_certs.p7c", 3)
Debug.Print strCertString
Debug.Print "CertThumb=" & x509CertThumb(strCertString)
Debug.Print "HashIssuerAndSN=" & x509HashIssuerAndSN(strCertString, PKI_HASH_SHA256)
X509_CertIsValidNow X509_CertThumb
Returns a bitfield containing the keyUsage flags for an X.509 certificate.
Public Declare Function X509_KeyUsageFlags Lib "diCrPKI.dll" (ByVal strCertFile As String) As Long
nRet = X509_KeyUsageFlags(strCertFile)
long __stdcall X509_KeyUsageFlags(const char *szCertFile);
If successful, it returns a positive integer containing the keyUsage flags; or 0 if no keyUsage flags are set; otherwise it returns a negative error code.
static X509.key_usage_flags(certfile)
The certificate may be in binary BER format or base64 PEM format. The presence of a key usage flag can be ascertained by AND'ing the result with the bitfield value for each flag.
digitalSignature 0x0001 nonRepudiation 0x0002 keyEncipherment 0x0004 dataEncipherment 0x0008 keyAgreement 0x0010 keyCertSign 0x0020 cRLSign 0x0040 encipherOnly 0x0080 decipherOnly 0x0100
These values are defined as PKI_X509_KEYUSAGE_DIGITALSIGNATURE, etc.
This shows how to find and display the key usage flags for a given certificate.
Dim nRet As Long Dim strCertName As String strCertName = "CarlRSASelf.cer" nRet = X509_KeyUsageFlags(strCertName) ' Show the result as a hex number Debug.Print "keyUsage flags are (0x" & Hex(nRet) & "):" ' Check all the keyUsage flags in turn If (nRet And PKI_X509_KEYUSAGE_DIGITALSIGNATURE) <> 0 Then Debug.Print "digitalSignature" If (nRet And PKI_X509_KEYUSAGE_NONREPUDIATION) <> 0 Then Debug.Print "nonRepudiation" If (nRet And PKI_X509_KEYUSAGE_KEYENCIPHERMENT) <> 0 Then Debug.Print "keyEncipherment" If (nRet And PKI_X509_KEYUSAGE_DATAENCIPHERMENT) <> 0 Then Debug.Print "dataEncipherment" If (nRet And PKI_X509_KEYUSAGE_KEYAGREEMENT) <> 0 Then Debug.Print "keyAgreement" If (nRet And PKI_X509_KEYUSAGE_KEYCERTSIGN) <> 0 Then Debug.Print "keyCertSign" If (nRet And PKI_X509_KEYUSAGE_CRLSIGN) <> 0 Then Debug.Print "cRLSign" If (nRet And PKI_X509_KEYUSAGE_ENCIPHERONLY) <> 0 Then Debug.Print "encipherOnly" If (nRet And PKI_X509_KEYUSAGE_DECIPHERONLY) <> 0 Then Debug.Print "decipherOnly" ' Alternatively, use X509_QueryCert to find these values as a string directly Debug.Print "Use X509_QueryCert..." Dim strOutput As String Dim strQuery As String Dim nChars As Long strQuery = "keyUsageString" nChars = X509_QueryCert("", 0, strCertName, strQuery, 0) If nChars < 0 Then Exit Sub ' ERROR strOutput = String(nChars, " ") nChars = X509_QueryCert(strOutput, Len(strOutput), strCertName, strQuery, 0) Debug.Print "X509_QueryCert('" & strQuery & "')=" & strOutput
For the S/MIME test file CarlRSASelf.cer, this displays
keyUsage flags are (0x61):
digitalSignature
keyCertSign
cRLSign
Use X509_QueryCert...
X509_QueryCert('keyUsageString')=digitalSignature,keyCertSign,cRLSign
Creates an X.509 certificate using subject's public key and issuer's private key files.
Public Declare Function X509_MakeCert Lib "diCrPKI.dll"
(ByVal strNewCertFile As String, ByVal strIssuerCertFile As String,
ByVal strSubjectPubKeyFile As String, ByVal strIssuerPriKeyFile As String,
ByVal nCertNum As Long, ByVal nYearsValid As Long,
ByVal strDistName As String, ByVal strExtensions As String,
ByVal KeyUsageFlags As Long,
ByVal strPassword As String, ByVal nOptions As Long) As Long
nRet = X509_MakeCert(strNewCertFile, strIssuerCertFile,
strSubjectPubKeyFile, strIssuerPriKeyFile, nCertNum, nYearsValid,
strDistName, strExtensions, KeyUsageFlags, strPassword, nOptions)
long __stdcall X509_MakeCert(const char *szNewCertFile, const char *szIssuerCertFile, const char *szSubjectPubKeyFile, const char *szIssuerPriKeyFile, long nCertNum, long nYearsValid, const char *szDistName, const char *szExtensions, long nKeyUsageFlags, const char *szPassword, long nOptions);
serialNumber is set in szExtensions."" or NULL to ignore.
| Option | To set |
|---|---|
| PKI_X509_KEYUSAGE_DIGITALSIGNATURE | digitalSignature |
| PKI_X509_KEYUSAGE_NONREPUDIATION | nonRepudiation |
| PKI_X509_KEYUSAGE_KEYENCIPHERMENT | keyEncipherment |
| PKI_X509_KEYUSAGE_DATAENCIPHERMENT | dataEncipherment |
| PKI_X509_KEYUSAGE_KEYAGREEMENT | keyAgreement |
| PKI_X509_KEYUSAGE_KEYCERTSIGN | keyCertSign |
| PKI_X509_KEYUSAGE_CRLSIGN | cRLSign |
| PKI_X509_KEYUSAGE_ENCIPHERONLY | encipherOnly |
| PKI_X509_KEYUSAGE_DECIPHERONLY | decipherOnly |
"" if key not encrypted [New in v12.0].sha1WithRSAEncryption (default - CAUTION)sha224WithRSAEncryptionsha256WithRSAEncryption [minimum recommended]sha384WithRSAEncryptionsha512WithRSAEncryptionmd5WithRSAEncryption [legacy, not recommended]md2WithRSAEncryption [legacy, definitely not recommended]RSA-PSS-SHA1RSA-PSS-SHA224RSA-PSS-SHA256RSA-PSS-SHA384RSA-PSS-SHA512ecdsaWithSHA1ecdsaWithSHA224ecdsaWithSHA256ecdsaWithSHA384ecdsaWithSHA512Ed25519 [New in v20.0]Ed448 [New in v22.0]basicConstraints subject type to be a CA (default = End Entity)basicConstraints extension (default = include)UTF8String (default = PrintableString)If successful, the return value is zero; otherwise it returns a nonzero error code.
static int dipki::X509::MakeCert (const std::string &newCertFile, const std::string &issuerCert, const std::string &subjectPubKeyFile, const std::string &issuerPriKeyFile, const std::string &password, int certNum, int yearsValid, const std::string distName, const std::string extns="", KeyUsageOptions keyUsageOptions=KeyUsageOptions::NoKeyUsageOption, SigAlg sigAlg=SigAlg::Default, CertOptions opts=CertOptions::Default_CertOpt)
static X509.make_cert(newcertfile, issuercert, subject_pubkeyfile, issuer_prikeyfile, password, certnum=0, yearsvalid=0, distname="", extns="", keyusage=KeyUsageFlags.NONE, sigalg=0, opts=0)
At least one valid attribute for the subject's distinguished name (DN) must be included. A version 1 certificate created using the PKI_X509_VERSION1 flag will, by definition, exclude any version 3 extensions.
If the PKI_X509_UTF8 flag is set,
each attribute of the subject's DN will be encoded as a UTF8String.
Otherwise the default encoding will be PrintableString or, if a non-printable character is specified,
then as either IA5String or T61String - see Specifying Distinguished Names for more details.
The encoding of the issuer's DN will be exactly as in the issuer's certficate.
If the PKI_X509_AUTHKEYID flag is set then an authorityKeyIdentifer extension will
be set if there is a corresponding subjectKeyIdentifer in the issuer's certificate.
Otherwise no such extension will be set.
The default validity period is from one minute ago by the system clock for a period of a whole number of years set by the nYearsValid parameter. This time will always have the seconds set to 01. A different validity period can be set using the notBefore and notAfter attributes in the szExtensions parameter (see X509 Extensions Parameter).
The serial number can be set to be an integer in the range 1 to 2,147,483,647 using the nCertNum parameter, or (once you have used these up!) it can be set to a larger value, perhaps a random large integer represented by a hexadecimal string, using the serialNumber attribute in the szExtensions parameter (see X509 Extensions Parameter).
As an alternative, you can create a new X.509 certificate using a PKCS-10 certificate signing request (CSR) file.
Pass the name of the CSR file in the szSubjectPubKeyFile parameter and set the szDistName empty "".
The empty distinguished name parameter is a flag that a CSR file is being used. See the example below.
[New in v12.0] Added support for unencrypted private key files for szIssuerPriKeyFile as well as encrypted ones.
Specify szPassword="" to flag an unencrypted key.
[New in v12.0] Added support for RSA-PSS and ECDSA signatures. Both the signing key and the subject's public key must be either both RSA keys for the RSA options, or both EC keys for the ECDSA signature options. The MGF hash function for RSA-PSS signatures in an X.509 certificate is always the same as the signature hash function. The signing key must be long enough to include the specified digest value and other encoding bytes. For example, a 1024-bit RSA key is too short to sign using RSA-PSS-SHA512 (see RSA signature and encryption schemes). Not all signature options provided may be accepted by other applications. Note also that both these signature schemes are probabilistic and each new signature contains randomly generated salt values, so you won't reproduce the same certificate even with identical inputs. Use the specialist options PKI_PSS_SALTLEN_ZERO and PKI_SIG_DETERMINISTIC with RSA-PSS and ECDSA, respectively, to force a deterministic (fixed) result.
[New in v12.3]
Added ability to specify an empty subjectName, to set extKeyUsage extension purposes in the X.509 Extensions Parameter,
and mark an arbitrary extension as critical.
Setting szDistName = "$" will create an X.509 document with an empty subjectName.
At least one field for a subject alternative name extension (altSubjectName) must be specified and the extension will automatically be marked critical.
char *dn = "$"; char *extns = "iPAddress=192.168.15.1;extKeyUsage=serverAuth,clientAuth,emailProtection,critical;";
[New in v20.5] Added ability to pass an internal key string for the subject's public key and signer's private key.
Dim nRet As Long
Dim strNewCertFile As String
Dim strIssuerCert As String
Dim strSubjectPubKeyFile As String
Dim strIssuerPriKeyFile As String
Dim strPassword As String
Dim nCertNum As Long
Dim nYearsValid As Long
Dim strDistName As String
Dim strEmail As String
strNewCertFile = "myuser.cer"
strIssuerCert = "myca.cer"
strSubjectPubKeyFile = "mykey.pub"
strIssuerPriKeyFile = "myca.p8e"
strPassword = "password" '!!
nCertNum = &H101
nYearsValid = 4
strDistName = "CN=My User;O=Test Org;OU=Unit;C=AU;L=My Town;S=State;E=myuser@testorg.com"
strEmail = "myuser@testorg.com"
nRet = X509_MakeCert(strNewCertFile, strIssuerCert, strSubjectPubKeyFile, strIssuerPriKeyFile, _
nCertNum, nYearsValid, strDistName, strEmail, 0, strPassword, 0)
If nRet <> 0 Then
Debug.Print nRet & " " & pkiErrorLookup(nRet)
Else
Debug.Print "Success, created X.509 cert " & strNewCertFile
End If
The above example will create a new X.509 certificate with filename myuser.cer.
The certificate will be issued by "myca" with serial number 257 (0x101)
for the subject with common name "My User", etc.
It will be valid from one minute ago today for 4 years.
The subject's public key in file mykey.pub will be included and it will be signed
by the issuer with certificate myca.cer and private key in file myca.p8e.
The next example in C uses the advanced szExtensions parameter to re-create exactly Alice's certificate from the S/MIME examples [SMIME-EX].
char *certname; char *issuercert = "CarlRSASelf.cer"; char *pubfile = "AlicePubRSA.pub"; char *epkfile = "CarlPrivRSASign.p8e"; char *password = "password"; char *certfile = "AliceRSA-dup.cer"; char *dn = "CN=AliceRSA"; char *extns = "rfc822name=AliceRSA@example.com;" "serialNumber=46346BC7800056BC11D36E2EC410B3B0;" "subjectKeyIdentifier=77D2B4D1B74C8A8AA3CE459DCEEC3CA03AE3FF50;" "notBefore=1999-09-19T01:08:47;" "notAfter=2039-12-31;" ; long keyUsage = PKI_X509_KEYUSAGE_DIGITALSIGNATURE + PKI_X509_KEYUSAGE_NONREPUDIATION; long lRet; char digest[PKI_SHA1_CHARS+1]; /* Make an end-user cert identical to RFC4134 AliceRSASignByCarl.cer */ certname = certfile; lRet = X509_MakeCert(certname, issuercert, pubfile, epkfile, 0, 99, dn, extns, keyUsage, password, PKI_X509_AUTHKEYID); assert(lRet == 0); printf("Created end-user X.509 certificate '%s'\n", certname); /* Check its SHA-1 thumbprint */ X509_CertThumb(certname, digest, sizeof(digest)-1, 0); printf("SHA-1 Thumb=%s\n", digest);
This should give the output
Created end-user X.509 certificate 'AliceRSA-dup.cer' SHA-1 Thumb=b30c48855055c2e64ce3196492d4b83831a6b3cb
Creates a self-signed X.509 certificate.
Public Declare Function X509_MakeCertSelf Lib "diCrPKI.dll"
(ByVal strNewCertFile As String, ByVal strPriKeyFile As String,
ByVal nCertNum As Long, ByVal nYearsValid As Long,
ByVal strDistName As String, ByVal strExtensions As String,
ByVal KeyUsageFlags As Long,
ByVal strPassword As String, ByVal nOptions As Long) As Long
nRet = X509_MakeCertSelf(strNewCertFile, strPriKeyFile,
nCertNum, nYearsValid,
strDistName, strExtensions, KeyUsageFlags, strPassword, nOptions)
long __stdcall X509_MakeCertSelf(const char *szNewCertFile, const char *szPriKeyFile, long nCertNum, long nYearsValid, const char *szDistName, const char *szExtensions, long nKeyUsageFlags, const char *szPassword, long nOptions);
serialNumber is set in szExtensions."" or NULL to ignore.
| PKI_X509_KEYUSAGE_DIGITALSIGNATURE | to set digitalSignature |
| PKI_X509_KEYUSAGE_NONREPUDIATION | to set nonRepudiation |
| PKI_X509_KEYUSAGE_KEYENCIPHERMENT | to set keyEncipherment |
| PKI_X509_KEYUSAGE_DATAENCIPHERMENT | to set dataEncipherment |
| PKI_X509_KEYUSAGE_KEYAGREEMENT | to set keyAgreement |
| PKI_X509_KEYUSAGE_KEYCERTSIGN | to set keyCertSign |
| PKI_X509_KEYUSAGE_CRLSIGN | to set cRLSign |
| PKI_X509_KEYUSAGE_ENCIPHERONLY | to set encipherOnly |
| PKI_X509_KEYUSAGE_DECIPHERONLY | to set decipherOnly |
"" if key not encrypted [New in v12.0].sha1WithRSAEncryption (default - CAUTION)sha224WithRSAEncryptionsha256WithRSAEncryption [minimum recommended]sha384WithRSAEncryptionsha512WithRSAEncryptionmd5WithRSAEncryption [legacy, not recommended]md2WithRSAEncryption [legacy, definitely not recommended]RSA-PSS-SHA1RSA-PSS-SHA224RSA-PSS-SHA256RSA-PSS-SHA384RSA-PSS-SHA512ecdsaWithSHA1ecdsaWithSHA224ecdsaWithSHA256ecdsaWithSHA384ecdsaWithSHA512Ed25519 [New in v20.0]Ed448 [New in v22.0]basicConstraints subject type to be a CA (default = End Entity)basicConstraints extension (default = include)UTF8String (default = PrintableString)If successful, the return value is zero; otherwise it returns a nonzero error code.
static int dipki::X509::MakeCertSelf (const std::string &newCertFile, const std::string &priKeyFile, const std::string &password, int certNum, int yearsValid, const std::string distName, const std::string extns="", KeyUsageOptions keyUsageOptions=KeyUsageOptions::NoKeyUsageOption, SigAlg sigAlg=SigAlg::Default, CertOptions opts=CertOptions::Default_CertOpt)
static X509.make_cert_self(newcertfile, prikeyfile, password, certnum, yearsvalid, distname, extns="", keyusage=0, sigalg=0, opts=0)
See the remarks for X509_MakeCert().
A self-signed certificate has the same Issuer and Subject distinguished name.
Add the PKI_X509_UTF8 flag to encode the distinguished names in UTF-8.
The BasicConstraints subject type will always be a CA for a version 3 self-signed certificate, unless
explicitly excluded with the PKI_X509_NO_BASIC flag.
Dim nRet As Long
Dim nKeyUsage As Long
nKeyUsage = PKI_X509_KEYUSAGE_DIGITALSIGNATURE + _
PKI_X509_KEYUSAGE_KEYCERTSIGN + PKI_X509_KEYUSAGE_CRLSIGN
nRet = X509_MakeCertSelf("myca.cer", "myca.p8e", 99, 10, _
"CN=My CA;O=Test Org;OU=Certificate Services", _
"", nKeyUsage, "password", 0)
If nRet <> 0 Then
Debug.Print nRet & " " & pkiGetLastError()
Else
Debug.Print "Success"
End If
The above example will create a new self-signed X.509 certificate with filename myca.cer.
The serial number will be 99.
It will be valid from today for 10 years.
The issuer's encrypted private key is in the file myca.p8e and has
the password "password". The new certificate will be signed using the private key
using the default sha1WithRSAEncryption algorithm.
The second example below shows how to specify a distinguished name using UTF-8-encoded CJK characters.
The PKI_X509_UTF8 flag must be used in this case.
Dim nRet As Long Dim nKeyUsage As Long Dim strDN As String ' Specify DN using chinese characters in UTF-8 ' CN=da wei (U+5927, U+536B) ' C=zhong guo (U+4E2D, U+56FD) strDN = "CN=#xE5A4A7E58DAB;C=#xe4b8ade59bbd" nKeyUsage = PKI_X509_KEYUSAGE_DIGITALSIGNATURE + PKI_X509_KEYUSAGE_KEYCERTSIGN + PKI_X509_KEYUSAGE_CRLSIGN nRet = X509_MakeCertSelf("myca-chinadavid.cer", "myca.p8e", _ &H888, 4, strDN, "", nKeyUsage, "password", PKI_X509_UTF8) If nRet <> 0 Then Debug.Print nRet & " " & pkiGetLastError() Else Debug.Print "Success" End If
Creates an X.509 Certificate Revocation List (CRL).
Public Declare Function X509_MakeCRL Lib "diCrPKI.dll" (ByVal strCrlFile As String, ByVal strIssuerCert As String, ByVal strIssuerKeyFile As String, ByVal strPassword As String, ByVal strRevokedCertList As String, ByVal strExtensions As String, ByVal nOptions As Long) As Long
nRet = X509_MakeCRL(strCrlFile, strIssuerCert,
strIssuerKeyFile, strPassword, strRevokedCertList, strExtensions, nOptions)
long __stdcall X509_MakeCRL(const char *szCrlFile, const char *szIssuerCert, const char *szIssuerKeyFile, const char *szPassword, const char *szRevokedCertList, const char *szExtensions, long nOptions);
serialNumber,revocationDate; ...
or the empty string "" for no revoked certificates. See the Remarks section below for more details.
;).
Valid attribute-value pairs are:
sha1WithRSAEncryption (default - CAUTION)sha224WithRSAEncryptionsha256WithRSAEncryption [minimum recommended]sha384WithRSAEncryptionsha512WithRSAEncryptionmd5WithRSAEncryption [legacy, not recommended]md2WithRSAEncryption [legacy, definitely not recommended]RSA-PSS-SHA1RSA-PSS-SHA224RSA-PSS-SHA256RSA-PSS-SHA384RSA-PSS-SHA512ecdsaWithSHA1ecdsaWithSHA224ecdsaWithSHA256ecdsaWithSHA384ecdsaWithSHA512Ed25519 [New in v20.0]Ed448 [New in v22.0]If successful, the return value is zero; otherwise it returns a nonzero error code.
static int dipki::X509::MakeCRL (const std::string &newFile, const std::string &issuerCert, const std::string &priKeyFile, const std::string &password, const std::string revokedCertList, const std::string extns="", SigAlg sigAlg=SigAlg::Default, CrlOptions opts=CrlOptions::Default_CrlOpt)
static X509.make_crl(newcrlfile, issuercert, prikeyfile, password, revokedcertlist="", extns="", sigalg=0, opts=0)
This function creates a version 1 CRL file with no extensions or cRLReason's. The parameter szRevokedCertList must be in the form
serialNumber,revocationDate;serialNumber,revocationDate; ...
The serialNumber must either be a positive decimal number (e.g. 123) or the number in hex format preceded by "#x"
(e.g. "#x0102deadbeef").
The revocation date must be in ISO date format
(e.g. 2009-12-31 or 2009-12-31T12:59:59Z).
By default, the lastUpdate time in the CRL is set to the time given by the system clock, and
nextUpdate time is left empty.
You can specify your own times using the lastUpdate and nextUpdate attributes
in the szExtensions parameter.
Times, if specified, must be in ISO 8601 format and are always interpreted as GMT times whether or not you add a "Z".
Dim nRet As Long Dim strCrlFile As String Dim strIssuerFile As String Dim strKeyFile As String Dim strPassword As String Dim strCertList As String Dim strExtension As String ' Create a new CRL dated with the current system time strCrlFile = "CarlsNew.crl" strIssuerFile = "CarlRSASelf.cer" strKeyFile = "CarlPrivRSASign.p8e" ' CAUTION: DO NOT HARD-CODE REAL PASSWORDS! strPassword = "password" strCertList = "1,2007-12-31; 2, 2009-12-31T12:59:59Z; 66000,2066-01-01; #x0102deadbeef,2010-02-28T01:01:59" nRet = X509_MakeCRL(strCrlFile, strIssuerFile, strKeyFile, strPassword, strCertList, "", 0) Debug.Print "X509_MakeCRL returns " & nRet & " (expected 0)" If (nRet = 0) Then Debug.Print "SUCCESS: New CRL file '" & strCrlFile & "' created." Else Debug.Print "ERROR: " & pkiErrorLookup(nRet) & ": " & pkiGetLastError() End If ' Create another CRL using specified times (NB these are GMT times, not local) strExtension = "thisUpdate=2010-04-01T12:00;nextUpdate=2010-05-01" strCrlFile = "Carl_20100401.crl" nRet = X509_MakeCRL(strCrlFile, strIssuerFile, strKeyFile, strPassword, strCertList, strExtension, 0) Debug.Print "X509_MakeCRL returns " & nRet & " (expected 0)" If (nRet = 0) Then Debug.Print "SUCCESS: New CRL file '" & strCrlFile & "' created." Else Debug.Print "ERROR: " & pkiErrorLookup(nRet) & ": " & pkiGetLastError() End If
The latter instruction should produce a CRL of the following form:
>certmgr -crl -v Carl_20100401.crl
==============CRL # 1 ==========
Issuer::
[0,0] 2.5.4.3 (CN) ValueType: 4
43 61 72 6C 52 53 41 'CarlRSA'
ThisUpdate::
Thu Apr 01 20:00:00 2010
NextUpdate::
Sat May 01 08:00:00 2010
SHA1 Thumbprint::
BAE05E5B E4F5E7A7 82F487CC 60F7BC31 0A643538
MD5 Thumbprint::
20E8251E 7959BE61 41441901 60DB7FBA
Version:: 0
SignatureAlgorithm:: 1.2.840.113549.1.1.5
SignatureAlgorithm.Parameters::
05 00 '..'
----- Entries -----
[0] SerialNumber:: 01
[0] RevocationDate:: Mon Dec 31 08:00:00 2007
[0] Extensions:: NONE
[1] SerialNumber:: 02
[1] RevocationDate:: Thu Dec 31 20:59:59 2009
[1] Extensions:: NONE
[2] SerialNumber:: 01 01 D0
[2] RevocationDate:: Fri Jan 01 08:00:00 2066
[2] Extensions:: NONE
[3] SerialNumber:: 01 02 DE AD BE EF
[3] RevocationDate:: Sun Feb 28 09:01:59 2010
[3] Extensions:: NONE
==============================================
CertMgr Succeeded
Note that the times given by CERTMGR are local, not GMT, and the output above is from a computer in a timezone 8 hours ahead of GMT. Different times will be shown in different timezones.
Queries an X.509 certificate file for selected information.
Public Declare Function X509_QueryCert Lib "diCrPKI.dll"
(ByVal strDataOut As String, ByVal nOutChars As Long,
ByVal strFileIn As String, ByVal strQuery As String, ByVal nOptions As Long) As Long
nRet = X509_QueryCert(strDataOut, nOutChars, strFileIn, strQuery,
nOptions) As Long
long __stdcall X509_QueryCert(char *szOutput, long nOutChars, const char *szCertFile, const char *szQuery, long nOptions);
If successful, the return value is a positive integer giving either the result itself (if the result is a number) or the number of characters in the output string (if the query is looking for a string). If the item queried is not present, the return value is zero. If there is an error (e.g. a missing or invalid certificate file), it returns a negative error code.
Public Function x509QueryCert (szCertFile As String, szQuery As String, Optional nOptions As Long = 0) As String
static std::string dipki::X509::QueryCert (const std::string &certFile, const std::string &query, OutputOpts outOpts=OutputOpts::Default_OutputOpt)
static X509.query_cert(filename, query, opts=0)
Valid queries are (case-insenitive):
| Query String | Returns | Data Type |
|---|---|---|
version | X.509 version number, e.g. 1 or 3. | Number |
serialNumber | Serial number in hex-encoded format | String |
signatureAlgorithm | Signature algorithm used, e.g. "sha1WithRSAEncryption". | String |
sigAlgId | ID of signature algorithm used, see PKI_SIG_* values | Number |
signatureValue | Signature value in hex-encoded format | String |
notBefore | Date on which the certificate validity period begins in format yyyy-mm-ddThh:nn:ssZ | String |
notAfter | Date on which the certificate validity period ends in format yyyy-mm-ddThh:nn:ssZ | String |
issuerName | Distinguished name (DN) of entity who has signed and issued the certificate | String |
subjectName | Distinguished name (DN) of the subject | String |
subjectPublicKeyAlgorithm | Algorithm used in subject's public key,
e.g. "dsa" or "rsaEncryption". | String |
subjectKeyIdentifier | The subject key identifier extension, if present, in hex-encoded format | String |
authorityKeyIdentifier | The authority key identifier extension, if present, in hex-encoded format | String |
rfc822Name | First internet mail address found contained in a subjectAltName extension, if present | String |
isCA | Returns 1 if the subject type is a CA, otherwise returns 0. | Number |
keyUsageString | keyUsage flags in text format, e.g. "digitalSignature,nonRepudiation" | String |
extKeyUsageString | extKeyUsage purposes in text format, e.g. "codeSigning,timeStamping" | String |
cRLDistributionPointsURI | First URI found in cRLDistributionPoints, if any | String |
authorityInfoAccessURI | First URI found in authorityInfoAccess, if any | String |
subjectAltName | Subject alternative name extension, if present. [New in v10.0] | String |
hashAlgorithm | Hash algorithm used in signature, e.g. "sha256". [New in v12.0] | String |
pssParams | Parameters used for RSA-PSS (if applicable). [New in v12.0] | String |
Some of these queries duplicate or complement existing functions:
"notBefore" = X509_CertIssuedOn()"notAfter" = X509_CertExpiresOn()"serialNumber" = X509_CertSerialNumber()"subjectName" = X509_CertSubjectName()"issuerName" = X509_CertIssuerName()The "raw" VBA/C function behaves differently depending on whether the output is a string or a number. If the result data type is a number then it returns the value directly. If the result is a string, then it sets szOutput and returns the number of characters in the string. The required number of characters can be found by passing zero for nOutChars or a null string for szOutput. ANSI C users must add one to this value when allocating memory.
Note that the VBA wrapper function and the C#/VB.NET methods always return a string, which is different from the behaviour of the raw VB6/C function.
To find out the type of data returned for a given query, use the PKI_QUERY_GETTYPE option.
The function will return either PKI_QUERY_NUMBER (1) or PKI_QUERY_STRING (2),
or a negative "invalid query" error.
For example
nRet = X509_QueryCert("", 0, "", "version", PKI_QUERY_GETTYPE);
will return PKI_QUERY_NUMBER.
If an attribute value is encoded in a multi-byte-character string format (such as UTF8String or BMPString),
the value will be expressed as a hexadecimal-encoded string [NB changed in v3.9]
preceded by the hash symbol ('#' U+0023), e.g.
"C=TW;O=E8 A1 8C E6 94 BF E9 99 A2" (v3.8 and earlier)
"C=TW;O=#E8A18CE694BFE999A2" (v3.9 and later)
Use the PKI_X509_LATIN1 option to return the string encoded in Latin-1, if possible, to help with display issues.
The output from the queries "issuerName" and "subjectName" using the PKI_X509_LDAP option
are suitable as content for the <X509IssuerName> and <X509SubjectName> nodes,
respectively, in the <X509Data> node of an XML-DSIG document.
This example queries information from a sample X.509 certificate file.
Dim nRet As Long Dim strOutput As String Dim strQuery As String Dim strCertFile As String strCertFile = "CarlRSASelf.cer" ' Make a large buffer to receive output strOutput = String(512, " ") strQuery = "version" nRet = X509_QueryCert(strOutput, Len(strOutput), strCertFile, strQuery, 0) Debug.Print strQuery & "=" & nRet strQuery = "serialNumber" nRet = X509_QueryCert(strOutput, Len(strOutput), strCertFile, strQuery, 0) If nRet <= 0 Then Exit Sub ' catch error Debug.Print strQuery & "=" & Left(strOutput, nRet) strQuery = "signatureAlgorithm" nRet = X509_QueryCert(strOutput, Len(strOutput), strCertFile, strQuery, 0) If nRet <= 0 Then Exit Sub ' catch error Debug.Print strQuery & "=" & Left(strOutput, nRet) strQuery = "notAfter" nRet = X509_QueryCert(strOutput, Len(strOutput), strCertFile, strQuery, 0) If nRet <= 0 Then Exit Sub ' catch error Debug.Print strQuery & "=" & Left(strOutput, nRet)
For the S/MIME test file CarlRSASelf.cer, the output is as follows
version=3 serialNumber=46346bc7800056bc11d36e2e9ff25020 signatureAlgorithm=sha1WithRSAEncryption notAfter=2039-12-31T23:59:59Z
To query the type of data returned for a given query.
Dim nRet As Long Dim strQuery As String ' Find out the data type for a given query strQuery = "version" nRet = X509_QueryCert("", 0, "", strQuery, PKI_QUERY_GETTYPE) Debug.Print "Type(" & strQuery & ")=" & nRet strQuery = "serialNumber" nRet = X509_QueryCert("", 0, "", strQuery, PKI_QUERY_GETTYPE) Debug.Print "Type(" & strQuery & ")=" & nRet strQuery = "NotAValidQuery" nRet = X509_QueryCert("", 0, "", strQuery, PKI_QUERY_GETTYPE) Debug.Print "Type(" & strQuery & ")=" & nRet
This should produce output
Type(version)=1 Type(serialNumber)=2 Type(NotAValidQuery)=-29
where 1 (PKI_QUERY_NUMBER) indicates a number, 2 (PKI_QUERY_STRING) indicates a string, and -29 (BAD_QUERY_ERROR) indicates an invalid query.
Debug.Print x509TextDumpToString("AliceRSASignByCarl.cer")
Debug.Print x509QueryCert("AliceRSASignByCarl.cer", "subjectName")
Debug.Print asn1TextDumpToString("AliceRSASignByCarl.cer")
X509_KeyUsageFlags X509_CertSubjectName
Reads an X.509 certificate into a base64 string from PKCS-7 "certs-only" data.
Public Declare Function X509_ReadCertStringFromP7Chain Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strP7cFile As String, ByVal nIndex As Long, ByVal nOptions As Long) As Long
nRet = X509_ReadCertStringFromP7Chain(strOutput, nOutChars, strP7cFile, nIndex, nOptions) As Long
long __stdcall X509_ReadCertStringFromP7Chain(char *szOutput, long nOutChars, const char *szP7cFile, long nIndex, long nOptions);
If successful and nIndex is greater than zero, the return value is a positive number indicating the number of characters in or required for the output string, which may be zero if no certificate could be found at the given index. However, if nIndex is zero, it returns the count of certificates found in the list. If an error occurred, it returns a negative error code.
Public Function x509ReadCertStringFromP7Chain (szP7cFile As String, nIndex As Long, Optional nOptions As Long = 0) As String
X509.ReadCertStringFromP7Chain Method
static std::string dipki::X509::ReadCertStringFromP7Chain (const std::string &inputFile, int index)
static X509.read_cert_string_from_p7chain(inputfile, index)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The output is a base64 string representation of the extracted X.509 certificate.
If nIndex is specified as a number greater than zero, the nIndex'th certificate found in the list, if any, will be extracted to a base64-encoded string which can be used to represent the X.509 certificate directly in this Toolkit. This function will also extract certificates from CMS signed data objects, too.
[New in v12.2] To find the number of certificates in the chain, use X509_GetCertCountInP7Chain. The old (deprecated) way to find the count of certificates was to set nIndex to zero.
The following example shows how to extract all the certificates from a PKCS-7 CertList file represented as a PEM string. All transactions are carried out in memory.
Dim strP7 As String Dim nCerts As Long Dim nChars As Long Dim nIndex As Long Dim strCert As String Dim strDigest As String * PKI_SHA1_CHARS Dim strQuery As String * 128 ' Input is a P7 chain file in PEM format ' bob.p7b (contains 2 X.509 certs: BobRSA and CarlRSA) strP7 = "-----BEGIN PKCS7-----" & _ "MIIERQYJKoZIhvcNAQcCoIIENjCCBDICAQExADALBgkqhkiG9w0BBwGgggQaMIICJzCCAZCgAwIB" & _ "AgIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdDYXJsUlNBMB4X" & _ "DTk5MDkxOTAxMDkwMloXDTM5MTIzMTIzNTk1OVowETEPMA0GA1UEAxMGQm9iUlNBMIGfMA0GCSqG" & _ "SIb3DQEBAQUAA4GNADCBiQKBgQCp4WeYPznVX/Kgk0FepnmJhcg1XZqRW/sdAdoZcCYXD72lItA1" & _ "hW16mGYUQVzPt7cIOwnJkbgZaTdt+WUee9mpMySjfzu7r0YBhjY0MssHA1lS/IWLMQS4zBgIFEjm" & _ "Txz7XWDE4FwfU9N/U9hpAfEF+Hpw0b6Dxl84zxwsqmqn6wIDAQABo38wfTAMBgNVHRMBAf8EAjAA" & _ "MA4GA1UdDwEB/wQEAwIFIDAfBgNVHSMEGDAWgBTp4JAnrHggeprTTPJCN04irp44uzAdBgNVHQ4E" & _ "FgQU6PS4Z9izlqQq8xGqKdOVWoYWtCQwHQYDVR0RBBYwFIESQm9iUlNBQGV4YW1wbGUuY29tMA0G" & _ "CSqGSIb3DQEBBQUAA4GBAHuOZsXxED8QIEyIcat7QGshM/pKld6dDltrlCEFwPLhfirNnJOIh/uL" & _ "t359QWHh5NZt+eIEVWFFvGQnRMChvVl52R1kPCHWRbBdaDOS6qzxV+WBfZjmNZGjOd539OgcOync" & _ "f1EHl/M28FAK3Zvetl44ESv7V+qJba3JiNiPzyvTMIIB6zCCAVSgAwIBAgIQRjRrx4AAVrwR024u" & _ "n/JQIDANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdDYXJsUlNBMB4XDTk5MDgxODA3MDAwMFoX" & _ "DTM5MTIzMTIzNTk1OVowEjEQMA4GA1UEAxMHQ2FybFJTQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw" & _ "gYkCgYEA5Ev/GLgkV/R3/25ze5NxXLwzGpKSciPYQUbQzRE6BLOOr4KdvVEeF3rydiwrhjmnvdeN" & _ "GlPs5ADV6OyiNrHt4lDiMgmKP5+ZJY+4Tqu5fdWWZdoWoMW+Dq5EW+9e9Kcpy4LdrETpqpOUKQ74" & _ "GNbIV17ydsTyEWA4uRs8HZfJavECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E" & _ "BAMCAYYwHQYDVR0OBBYEFOngkCeseCB6mtNM8kI3TiKunji7MA0GCSqGSIb3DQEBBQUAA4GBALee" & _ "1ATT7Snk/4mJFS5M2wzwSA8yYe7EBOwSXS3/D2RZfgrD7Rj941ZAN6cHtfA4EmFQ7e/dP+MLuGGl" & _ "pJs85p6cVJq2ldbabDu1LUU1nUkBdvq5uTH5+WsSU6D1FGCbfco+8lNrsDdvreZ019v6WuoUQWNd" & _ "zb7IDsHaao1TNBgCMQA=" & _ "-----END PKCS7-----" ' Get count of certs in P7 chain - new function in [v12.2] nIndex = 0 nCerts = X509_GetCertCountInP7Chain(strP7, 0) Debug.Print "nCerts=" & nCerts ' Read all certs For nIndex = 1 To nCerts ' Find required length of buffer nChars = X509_ReadCertStringFromP7Chain(ByVal 0&, 0, strP7, nIndex, 0) Debug.Print "X509_ReadCertStringFromP7Chain(" & nIndex & ") returns " & nChars ' Allocate memory/pre-dimension strCert = String(nChars, " ") nChars = X509_ReadCertStringFromP7Chain(strCert, Len(strCert), strP7, nIndex, 0) ' Cert is in a base64 string Debug.Print Left(strCert, 150) & "..." ' Query the cert for subject name nChars = X509_QueryCert(strQuery, Len(strQuery), strCert, "subjectName", 0) Debug.Print "subjectName='" & Left(strQuery, nChars) & "'" ' Compute the SHA-1 thumbprint of the cert nChars = X509_CertThumb(strCert, strDigest, Len(strDigest), 0) Debug.Print "SHA-1(cert)=" & Left(strDigest, nChars) Next
This should result in output as follows:
nCerts=2 X509_ReadCertStringFromP7Chain(1) returns 740 MIICJzCCAZCgAwIBAgIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdDYXJsUlNBMB4XDTk5MDkxOTAxMDkwMloXDTM5MTIzMTIzNTk1OVowETEPMA0GA1UEAxMGQm... subjectName='CN=BobRSA' SHA-1(cert)=63f046d2dd7042e51fdc26a511ef7c81ea622d8b X509_ReadCertStringFromP7Chain(2) returns 660 MIIB6zCCAVSgAwIBAgIQRjRrx4AAVrwR024un/JQIDANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdDYXJsUlNBMB4XDTk5MDgxODA3MDAwMFoXDTM5MTIzMTIzNTk1OVowEjEQMA4GA1UEAxMHQ2... subjectName='CN=CarlRSA' SHA-1(cert)=4110908f77c64c0edfc2de6273bfa9a98a9c5ce5
Dim strCertString As String
strCertString = x509ReadStringFromFile("AliceRSASignByCarl.cer")
Debug.Print strCertString
Debug.Print "CertThumb=" & x509CertThumb(strCertString)
strCertString = x509ReadCertStringFromP7Chain("alice_bob_carl_certs.p7c", 3)
Debug.Print strCertString
Debug.Print "CertThumb=" & x509CertThumb(strCertString)
Debug.Print "HashIssuerAndSN=" & x509HashIssuerAndSN(strCertString, PKI_HASH_SHA256)
'Invalid index
strCertString = x509ReadCertStringFromP7Chain("alice_bob_carl_certs.p7c", 0)
Debug.Print "[" & strCertString & "]"
Dim strP7File As String
Dim nIndex As Long
Dim nCerts As Long
strP7File = "alice_bob_carl_certs.p7c"
' Call core fn with zero index to find count
nCerts = X509_ReadCertStringFromP7Chain("", 0, strP7File, 0, 0)
Debug.Print "nCerts=" & nCerts
For nIndex = 1 To nCerts
strCertString = x509ReadCertStringFromP7Chain(strP7File, nIndex)
Debug.Print "subjectName: " & x509QueryCert(strCertString, "subjectName")
Next
X509_GetCertFromP7Chain X509_GetCertCountInP7Chain CMS_QuerySigData
Reads an X.509 certificate into a base64 string from PKCS-12 PFX/.p12 data.
Public Declare Function X509_ReadCertStringFromPFX Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strPfxFile As String, ByVal strPassword As String, ByVal nOptions As Long) As Long
nRet = X509_ReadCertStringFromPFX(strOutput, nOutChars, strPfxFile, strPassword, nOptions) As Long
long __stdcall X509_ReadCertStringFromPFX(char *szOutput, long nOutChars, const char *szPfxFile, const char *szPassword, long nOptions);
"" if certificate is not encryptedIf successful, the return value is a positive number indicating the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function x509ReadCertStringFromPFX (szPfxFile As String, szPassword As String, Optional nOptions As Long = 0) As String
X509.ReadCertStringFromPFX Method
static std::string dipki::X509::ReadCertStringFromPFX (const std::string &inputFile, const std::string &password)
static X509.read_cert_string_from_pfx(inputfile, password)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The default behaviour is to extract one certificate from the PFX file and output as a base64 string representation of the extracted X.509 certificate.
It will attempt to find a matching certificate for any private key, otherwise it will save
the first pkcs-12-certBag found in the PFX file containing a x509Certificate.
Both unencrypted certificates and certificates encrypted with the weak 40-bit encryption used by "default"
in Microsoft and OpenSSL PKCS-12 files are supported, but not any other encryption algorithm.
If no certificate can be found the function will return a negative NO_DATA_ERROR error code.
Dim strPfx As String Dim nChars As Long Dim strCert As String Dim strDigest As String * PKI_SHA1_CHARS Dim strQuery As String * 128 Dim strPassword As String ' Input is a PFX file in PEM format ' bob.pfx (password="password") strPfx = "-----BEGIN PKCS12-----" & _ "MIIGhAIBAzCCBkoGCSqGSIb3DQEHAaCCBjsEggY3MIIGMzCCAv8GCSqGSIb3DQEHBqCCAvAwggLsAgEAMIIC5QYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIawU" & _ "AVTFvAiECAggAgIICuNwEuFcRnZamZyMyIn+vH+wC5BVUtZAWNrlIqToezF7cYqt/18+HXB/46nllz+qUD3Dv9rS78MnPeAM47afFRTricHsiOpE+2eXf32lxduoF5+" & _ "CLS3S7TAhRUMp2Fh18LlukzK9lY67BGfU9Y3yCukTmwVXqe49dkj8y9JjVJhXnoc2c7eOk3o5RjXHFsAMHwirqdsESHstrDZYLMVGw5HnAamY7zQd8WUpIweAFaEDLJ" & _ "fyzqY1/LTL/txvZ9VQ/B/36HKyEpoIvuH6iOCBkebpJwWSkkffuVFbUfMLguMztL/sf+jE2NiuljSBJ9pTNsZziZWERb6CxZH0a2xkkBTciXM5Dl5efWL0GmBg+aJSI" & _ "yh+Gw5W8Q7gmnH6H9myszvW9uYv/epwCbIpHd0dRHPbL3fR4KGhFexq24tAG86tDqPKb6H6n0lSA+Oq46SwZ00xIFpVcFaO/8yVqf6+JRDGoZ55aAZF6OCi7R1GvI+6" & _ "pzz37pvP7SWfqVSuXCTNQq9uKw97SH5YftQ9hkELQ4vHCjFh4UJSBUCZgDtqR1uB/+44H5UpP8KvbETaOFJszMxsqXBMqc1uEODSNg+EHEx+yg7Bx1CcNrm+6rtThC4" & _ "9+ow18HDMxbn3lAw1ooblANvSzR4YTt68N/4dtwROOdXjwKzyg03qWK2sJaiH5LzbB5MMmrdAChb9dLoRKBN2LREob7KRKEs6v51IW1yq4UCwSmpP+RbchZwIoKVXx/" & _ "MYKjVqzGfZAgBRpXEq/KH/8R+ttFPKdab2GAEjd7hIOmetp5einQmK4C7JYE6Uyabf1IImtVhBw2dGU3GiM2zSIGqCx3bmYETZheMTAV9MMVUYe8gQeEpbXM4GAnwX0" & _ "wpS0aYapzGeA/62X2nFh21eRHVzUcf0miXVvyOy6a1vj6O6N5F1jVaCV3jCCAywGCSqGSIb3DQEHAaCCAx0EggMZMIIDFTCCAxEGCyqGSIb3DQEMCgECoIICpjCCAqI" & _ "wHAYKKoZIhvcNAQwBAzAOBAjw/dx4SlLcWwICCAAEggKALm91I8gYuPpRTCSn5pN4OQBLbI6jSW+9FGeNYvOy/+Pt3Oq0i15ZXZZez7dP8rdb0tmTCSZwVPIwtJRKxY" & _ "UNaTppUTWZhXhnmeTMtSZpFuKmo6UhW8lGUcg45sO5UKUtdH0/UgewaSUfV4L06vp4j7Fugwbp666seJJ/9vQwMAxoqj0blxNNmASAcW7yj/lA2/p4KuGlnGkv4MSW5" & _ "ViH7T24VeFXTzyFFR7UR1Nw9Blr5jdr7b2rZSdTj0GeHZ/L3FksFWJocl8PEEL4ZdVscbvO+l7vtbeBz0y9TDr/HUwt2tfqXgjckVVoJhmsczJXrG5Ai+brKnGQ7R5u" & _ "IpIsqd9O6EpG68VMMGA5iSKsLYtibieqom8mRO00sFiQharxONEdveY+3O98nG6xzHlaBdNbxVo38Y+4LK6Gc81dUWYwss3ajdiJWe0+TYQjMPF72eWctcQAoTxITpd" & _ "/j6rD7EmvLVyPIR46L4w6Gb/uz5G1T1UiLoh9luM1nRKKICyo2XllZDNO0msaub7DH1xzJzEy2OT9cwChqYfKKeWEE2BWL699fmq5RMCbIQVtE2bJDP8obu9j6HLskC" & _ "iZcJm6nC7IKS1pQ2BA/JJVKxC8ADuLOAOdicWquDd8MWL5a9HpXd5TtUlfiRecTw8IRozTLaoDVlhaYNGPzwkjL9zZ+Up5Uy6HHXMDb0aD0fgvMqdAspB1+Xlt2RgP6" & _ "CnEH2hwQqGFoA8TtijeS+DtdMy8BxJ7g1fiEH0+4UISl1vymjPI1MJCI1VlFLvpjZvKHluwjgp1SHk3tFRJLJ8a/eApvmscKXSlxcYz+5Bv8dxPGdhO/KOLQS7XZ4a8" & _ "VSg977WS1jFYMCMGCSqGSIb3DQEJFTEWBBRj8EbS3XBC5R/cJqUR73yB6mItizAxBgkqhkiG9w0BCRQxJB4iAEIAbwBiACcAcwAgAGYAcgBpAGUAbgBkAGwAeQAgAEk" & _ "ARDAxMCEwCQYFKw4DAhoFAAQUaHSMUJ415FfKGv3cZpwloKDmqgYECAreM3EkHVjCAgIIAA==" & _ "-----END PKCS12-----" ' Read in cert as string from PFX/P12 data ' Find required length of buffer nChars = X509_ReadCertStringFromPFX(ByVal 0&, 0, strPfx, "password", 0) Debug.Print "X509_ReadCertStringFromPFX() returns " & nChars ' Allocate memory/pre-dimension strCert = String(nChars, " ") nChars = X509_ReadCertStringFromPFX(strCert, Len(strCert), strPfx, "password", 0) ' Cert is in a base64 string Debug.Print Left(strCert, 150) & "..." ' Query the cert for subject name nChars = X509_QueryCert(strQuery, Len(strQuery), strCert, "subjectName", 0) Debug.Print "subjectName='" & Left(strQuery, nChars) & "'" ' Compute the SHA-1 thumbprint of the cert nChars = X509_CertThumb(strCert, strDigest, Len(strDigest), 0) Debug.Print "SHA-1(cert)=" & Left(strDigest, nChars)
This should result in output as follows:
X509_ReadCertStringFromPFX() returns 740 MIICJzCCAZCgAwIBAgIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdDYXJsUlNBMB4XDTk5MDkxOTAxMDkwMloXDTM5MTIzMTIzNTk1OVowETEPMA0GA1UEAxMGQm... subjectName='CN=BobRSA' SHA-1(cert)=63f046d2dd7042e51fdc26a511ef7c81ea622d8b
Dim strCertString As String
strCertString = x509ReadCertStringFromPFX("alice.p12", "password")
Debug.Print strCertString
Debug.Print "CertThumb=" & x509CertThumb(strCertString)
Debug.Print "HashIssuerAndSN=" & x509HashIssuerAndSN(strCertString)
Creates a base64 string of an X.509 certificate file.
Public Declare Function X509_ReadStringFromFile Lib "diCrPKI.dll"
(ByVal strOutput As String, ByVal nOutChars As Long, ByVal strCertFile As String, ByVal nOptions As Long) As Long
nRet = X509_ReadStringFromFile(strOutput, nOutChars, strCertFile, nOptions) As Long
long __stdcall X509_ReadStringFromFile(char *szOutput, long nOutChars, const char *szCertFile, long nOptions);
If successful, the return value is a positive number indicating the number of characters in the output string; otherwise it returns a negative error code.
Public Function x509ReadStringFromFile (szCertFile As String, Optional nOptions As Long = 0) As String
X509.ReadStringFromFile Method
static std::string dipki::X509::ReadStringFromFile (const std::string &certFile)
static X509.read_string_from_file(certfilename)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
This function reads in the complete X.509 certificate as a continuous base64 string. The same certificate will always produce exactly the same string. This string can be used, for example, when creating an XML file which requires the certificate as an attribute, e.g.
<?xml version="1.0" encoding="UTF-8"?>
<Comprobante fecha="2005-09-02T16:30:00" folio="1" noAprobacion="1"
noCertificado="00001000000000000114"
certificado="MIIDWjCCAkKgAwIBAgIUMDAwMDExMDAwMDAyMDA..."
serie="A" version="1.0">
The output string must be long enough to receive the complete output or a SHORT_BUF_ERROR error will result.
This example reads in the base64 string from the SAT Mexico test certificate and displays it.
It then saves the string as a new certificate and uses the
X509_CertThumb
function to check that the two files are identical.
Dim nRet As Long Dim strCertString As String Dim strCertFile As String Dim strNewFile As String Dim strThumb1 As String Dim strThumb2 As String strCertFile = "aaa010101aaa_CSD.cer" ' Read in certificate file's data to a string nRet = X509_ReadStringFromFile("", 0, strCertFile, 0) Debug.Print "X509_ReadStringFromFile returns " & nRet If nRet <= 0 Then Exit Sub ' ERROR strCertString = String(nRet, " ") nRet = X509_ReadStringFromFile(strCertString, Len(strCertString), strCertFile, 0) Debug.Print "For certificate '" & strCertFile & "':" Debug.Print strCertString ' Save the string to a new certificate file, this time in PEM format strNewFile = "aaa010101aaa_CSD.pem.cer" nRet = X509_SaveFileFromString(strNewFile, strCertString, PKI_X509_FORMAT_PEM) Debug.Print "X509_SaveFileFromString returns " & nRet If nRet = 0 Then Debug.Print "Created new certificate file '" & strNewFile & "'" End If ' Check that the two certificate files are identical by computing their SHA-1 thumbprints strThumb1 = String(PKI_SHA1_CHARS, " ") strThumb2 = String(PKI_SHA1_CHARS, " ") nRet = X509_CertThumb(strCertFile, strThumb1, Len(strThumb1), 0) nRet = X509_CertThumb(strNewFile, strThumb2, Len(strThumb2), 0) Debug.Print "SHA-1(old)=" & strThumb1 Debug.Print "SHA-1(new)=" & strThumb2 If strThumb1 = strThumb2 Then Debug.Print "Certificates are identical" Else Debug.Print "ERROR: certificates do not match" End If
The output should look like this (the 1152-character certificate string has been edited)
X509_ReadStringFromFile returns 1152 For certificate 'aaa010101aaa_CSD.cer': MIIDWjCCAkKgAwIBAgIUMDAwMDEx...7D5F8SB7Li3zt9vbbMzBc5xGg== X509_SaveFileFromString returns 0 Created new certificate file 'aaa010101aaa_CSD.pem.cer' SHA-1(old)=5791650d63340129568c1eecc6566b2fdd8bbd4c SHA-1(new)=5791650d63340129568c1eecc6566b2fdd8bbd4c Certificates are identical
Dim strCertString As String
strCertString = x509ReadStringFromFile("AliceRSASignByCarl.cer")
Debug.Print strCertString
Debug.Print "CertThumb=" & x509CertThumb(strCertString)
strCertString = x509ReadCertStringFromP7Chain("alice_bob_carl_certs.p7c", 3)
Debug.Print strCertString
Debug.Print "CertThumb=" & x509CertThumb(strCertString)
Debug.Print "HashIssuerAndSN=" & x509HashIssuerAndSN(strCertString, PKI_HASH_SHA256)
Creates an X.509 certificate file from its base64 string representation.
Public Declare Function X509_SaveFileFromString Lib "diCrPKI.dll"
(ByVal strNewCertFile As String, ByVal strCertString As String, ByVal nOptions As Long) As Long
nRet = X509_SaveFileFromString(strNewCertFile, strCertString, nOptions)
long __stdcall X509_SaveFileFromString(const char *szNewCertFile, const char *szCertString, long nOptions);
If successful, the return value is zero; otherwise it returns a negative error code.
X509.SaveFileFromString Method
static int dipki::X509::SaveFileFromString (const std::string &newCertFile, const std::string &certString, bool inPEMFormat=false)
static X509.save_file_from_string(newcertfile, certstring, in_pem_format=False)
This function creates a new X.509 certificate file from a base64 string.
It is the reverse of X509_ReadStringFromFile().
Any existing file of the same name will be overwritten without warning.
The default option (nOptions = 0) is to save the file in binary (BER, DER) format.
A PEM format file will start with -----BEGIN CERTIFICATE----- and will contain the same
base64 characters as in the certificate string.
Both formats should be equally readable with the usual certificate manager programs
and both should have the same message digest "thumbprint".
See the example in X509_ReadStringFromFile.
Dumps details of an X.509 certificate (or a X.509 certificate revocation list (CRL) or a PKCS-10 certificate signing request (CSR)) to a text file.
Public Declare Function X509_TextDump Lib "diCrPKI.dll" (ByVal strFileOut As String, ByVal strCertFile As String, ByVal nOptions As Long) As Long
nRet = X509_TextDump(strFileOut, strCertFile, nOptions)
long __stdcall X509_TextDump(const char *szFileOut, const char *szCertFile, long nOptions);
If successful, the return value is zero; otherwise it returns a nonzero error code.
static X509.text_dump(outputfile, certfile, opts=0)
The input file may be in binary BER/DER format or base64 PEM file format, or may be passed in base64 representation or as a PEM string. It produces a text file containing the basic details of an X.509 certificate, X.509 certificate revocation list (CRL) or PKCS-10 certificate signing request (CSR).
[New in v12.3] The notation [!] denotes a critical extension, e.g. Key Usage[!]:.
Dim nRet As Long
Dim strInputFile As String
Dim strOutFile As String
strInputFile = "AliceRSASignByCarl.cer"
strOutFile = "dump-AliceRSASignByCarl.cer.txt"
Debug.Print "File=" & strInputFile
nRet = X509_TextDump(strOutFile, strInputFile, 0)
Debug.Print "X509_TextDump returns " & nRet
The above example produces a text file with the following contents:
X.509 CERTIFICATE
Version: 3
Serial Number:
#x46346BC7800056BC11D36E2EC410B3B0
Issuer:
CN=CarlRSA
Subject:
CN=AliceRSA
Validity:
NotBefore: 1999-09-19T01:08:47Z
NotAfter: 2039-12-31T23:59:59Z
Subject Public Key Algorithm: rsaEncryption
RSA key length: 1024 bits
Modulus:
E0 89 73 39 8D D8 F5 F5 E8 87 76 39 7F 4E B0 05
BB 53 83 DE 0F B7 AB DC 7D C7 75 29 0D 05 2E 6D
12 DF A6 86 26 D4 D2 6F AA 58 29 FC 97 EC FA 82
51 0F 30 80 BE B1 50 9E 46 44 F1 2C BB D8 32 CF
C6 68 6F 07 D9 B0 60 AC BE EE 34 09 6A 13 F5 F7
05 05 93 DF 5E BA 35 56 D9 61 FF 19 7F C9 81 E6
F8 6C EA 87 40 70 EF AC 6D 2C 74 9F 2D FA 55 3A
B9 99 77 02 A6 48 52 8C 4E F3 57 38 57 74 57 5F
Exponent:
01 00 01
X509v3 Extensions:
Subject Type: End Entity
Key Usage[!]:
digitalSignature,nonRepudiation
Authority Key Identifier:
e9e09027ac78207a9ad34cf242374e22ae9e38bb
Subject Key Identifier:
77d2b4d1b74c8a8aa3ce459dceec3ca03ae3ff50
Subject Alternative Name:
RFC822 Name: AliceRSA@example.com
Signature Algorithm: sha1WithRSAEncryption
Signature Hash Algorithm: sha1
Signature Value:
3E 70 47 A8 48 CC 13 58 8F CA 51 71 6B 4E 36 18
5D 04 7E 80 B1 8D 4D CC CA A3 8F CC 7D 56 C8 BC
CF 6E B3 1C 59 A9 20 AA 05 81 A8 4E 25 AD A7 70
14 75 2F F5 C7 9B D1 0E E9 63 D2 64 B7 C6 66 6E
73 21 54 DF F4 BA 25 5D 7D 49 D3 94 6B 22 36 74
73 B8 4A EC 2F 64 ED D3 3D D2 A7 42 C5 E8 37 8A
B4 DB 9F 67 E4 BD 9F F9 FE 74 EF EA F9 EE 63 6A
D8 3F 4B 25 09 B5 D8 1A 76 AE EB 9B DB 49 B0 22
SHA-1 Thumbprint:
b30c48855055c2e64ce3196492d4b83831a6b3cb
SHA-256 Thumbprint:
10e79a9993c26a87f2109ec1e81e0ac3ada0ee1bac1fe57fd85450e2c7c2406b
Dumps details of an X.509 certificate or a X.509 certificate revocation list (CRL) or a PKCS-10 certificate signing request (CSR) to a string.
Public Declare Function X509_TextDumpToString Lib "diCrPKI.dll" (ByVal strOutput As String, ByVal nOutChars As Long, ByVal strCertFile As String, ByVal nOptions As Long) As Long
nRet = X509_TextDumpToString(strOutput, nOutChars, strCertFile, nOptions)
long __stdcall X509_TextDumpToString(char *szOutput, long nOutChars, const char *szCertFile, long nOptions);
If successful, the return value is the number of characters in or required for the output string; otherwise it returns a negative error code.
Public Function x509TextDumpToString (szCertFile As String, Optional nOptions As Long = 0) As String
static std::string dipki::X509::TextDumpToString (const std::string &certFile, OutputOpts outOpts=OutputOpts::Default_OutputOpt)
static X509.text_dump_tostring(certfile, opts=0)
For the "raw" VBA/C function, the user must allocate an output string buffer szOutput of the required length. Specify a zero nOutChars or an empty string for szOutput to find the required length. ANSI C users must add one to this value when allocating memory.
The input file may be a an X.509 certificate, X.509 certificate revocation list (CRL) or PKCS-10 certificate signing request (CSR) and may be a file in binary BER/DER or base64 PEM file format, or may be passed in base64 representation or as a PEM string.
The output string must be long enough to receive the complete output or a SHORT_BUF_ERROR error will result.
Dim strInputFile As String Dim strBuffer As String Dim nChars As Long strInputFile = "AliceRSASignByCarl.cer" Debug.Print "File=" & strInputFile ' Query for required length nChars = X509_TextDumpToString("", 0, strInputFile, PKI_X509_DECIMAL) Debug.Print "X509_TextDumpToString returns " & nChars ' Dimension output buffer strBuffer = String(nChars, " ") nChars = X509_TextDumpToString(strBuffer, Len(strBuffer), strInputFile, PKI_X509_DECIMAL) Debug.Print strBuffer
File=AliceRSASignByCarl.cer X509_TextDumpToString returns 1692 X.509 CERTIFICATE Version: 3 Serial Number: 93318145165434344057210696409401045936 Issuer: CN=CarlRSA ...[cut]...
Debug.Print x509TextDumpToString("AliceRSASignByCarl.cer")
Debug.Print x509QueryCert("AliceRSASignByCarl.cer", "subjectName")
Debug.Print asn1TextDumpToString("AliceRSASignByCarl.cer")
Validates a certificate path.
Public Declare Function X509_ValidatePath Lib "diCrPKI.dll" (ByVal strCertListOrP7File As String, ByVal strTrustedCert As String, ByVal nOptions As Long) As Long
nRet = X509_ValidatePath(strCertListOrP7File, strTrustedCert, nOptions)
long __stdcall X509_ValidatePath(const char *szCertListOrP7File, const char *szTrustedCert, long nOptions);
Zero (0) if the certification path is valid.
If the certificates are otherwise of correct format but the validation fails, the return value is PKI_X509_INVALID (+43 = CERT_PATH_ERROR);
otherwise a negative error code.
X509.ValidatePath Method (String)
static X509.cert_path_is_valid(certlist, trustedcert="", no_timecheck=False)
A basic validation is carried out confirming that the subject of certificate x is the issuer of certificate x+1,
that certficate x was signed by certificate x-1, and that each certificate is valid as at the time on the system clock.
Only distinguished names are used to identify subjects and issuers, not alternative names or IDs.
Certificate policies are ignored and no checks are made for revocation
(use X509_CheckCertInCRL() individually).
The order of the certificates in the input list is not important, but a complete chain must exist.
Note that the certificates must either all exist inside one .p7c cert chain file, or exist individually as .cer files.
In the latter case, specify all the file names in a semi-colon-separated list.
You can also pass the individual certificate information in its base64 representation rather than filenames, as in
szCertList="MIHgMIGaAgE...se348UN/Q=;MIHgMIGaAgEB...9j8eEtvHw=;...etc.
The szTrustedCert parameter is required unless a self-signed trust anchor is included in the list.
If there is no self-signed certificate,
then you must specify a trusted certificate which has signed the certificate at the top of your chain.
If specified, this must exist separately as a .cer file.
All certificates must be valid at the time the check is made or an error will result, unless
the PKI_X509_NO_TIMECHECK option is used.
More information on the reason for an invalid certification path may be available by using
PKI_LastError().
[Changed in v12.0] If the certificates are otherwise of correct format but the validation fails, this function returns CERT_PATH_ERROR (+43). Previous versions would return +1.
Dim nRet As Long Dim strP7cFile As String Dim strTrustedCert As String Dim strCertList As String ' A p7c "certs-only" file which includes a self-signed cert strP7cFile = "testcerts1.p7c" nRet = X509_ValidatePath(strP7cFile, "", 0) Debug.Print "X509_ValidatePath returns " & nRet & " (expected 0)" ' Same again but specify the trusted root cert ' (which is the same as the self-signed cert in the p7c file) strP7cFile = "testcerts1.p7c" strTrustedCert = "testcert00.cer" nRet = X509_ValidatePath(strP7cFile, strTrustedCert, 0) Debug.Print "X509_ValidatePath returns " & nRet & " (expected 0)" ' Specify a cert list - testcert00.cer is the self-signed cert strCertList = "testcert00.cer;testcert03.cer;testcert01.cer;testcert02.cer" nRet = X509_ValidatePath(strCertList, "", 0) Debug.Print "X509_ValidatePath returns " & nRet & " (expected 0)" ' Same again but specify the trusted root cert (this time it is not in the list) strCertList = "testcert01.cer;testcert02.cer;testcert03.cer" strTrustedCert = "testcert00.cer" nRet = X509_ValidatePath(strCertList, strTrustedCert, 0) Debug.Print "X509_ValidatePath returns " & nRet & " (expected 0)"
X509_VerifyCert X509_CertIsValidNow X509_CheckCertInCRL
Verifies that an X.509 certificate - or X.509 certificate revocation list (CRL) or PKCS-10 certificate signing request (CSR) - has been signed by its issuer.
Public Declare Function X509_VerifyCert Lib "diCrPKI.dll"
(ByVal strCertToVerify As String, ByVal strIssuerCert As String,
ByVal nOptions As Long) As Long
nRet = X509_VerifyCert(strCertToVerify,
strIssuerCert, nOptions)
long __stdcall X509_VerifyCert(const char *szCertToVerify, const char *szIssuerCert, long nOptions);
"" for a PKCS#10 CSR.
Zero (0) if the certificate's signature is valid.
If the certificate is otherwise of correct format but the validation fails, the return value is
PKI_X509_VERIFY_FAILURE (+22 = SIGNATURE_ERROR);
otherwise it returns a positive error code.
static X509.cert_is_verified(certfile, issuercert)
This function verifies only that the certificate was signed by the owner of the public key in the issuer's certificate.
It does not check the validity dates of either
certificate (to do that use X509_CertIsValidNow()).
Nor does it check that the certficate has been revoked
(to do that use X509_CheckCertInCRL()).
Only certificates signed with supported signature algorithms can be checked:
see Supported Algorithms.
The certificate file may be in binary BER/DER format or base64 PEM file format,
or may be passed in base64 representation or as a PEM string.
This function can also be used to verify that an X.509 Certificate Revocation List (CRL) has been signed by the owner of the issuer's certificate or that the self-signed signature in a PKCS#10 Certificate Signing Request (CSR) is valid. Just pass the name of the file (or its PEM string form) as szCertToVerify.
[New in v12.0] A PKCS#10 Certificate Signing Request (CSR) contains its own public key which it can use to verify its own signature directly.
To verify a CSR, pass its name in szCertToVerify and set szIssuerCert="". See example below.
[Changed in v12.0] If the certificate is otherwise of correct format but the validation fails, this function returns SIGNATURE_ERROR (22). Previous versions would return -1.
This example verifies that the certificate myuser.cer has been signed by the owner of myca.cer.
' Returns 0 if OK, PKI_X509_VERIFY_FAILURE if fails to validate, or +ve other error Dim nRet As Long nRet = X509_VerifyCert("myuser.cer", "myca.cer", 0) If nRet = 0 Then Debug.Print "Verification is OK" ElseIf nRet = PKI_X509_VERIFY_FAILURE Then Debug.Print "Cert not issued by this Issuer" Else Debug.Print "Error: " & nRet & pkiGetLastError() End If
This example verifies the signature in a PKCS#10 Certificate Signing Request.
Dim nRet As Long
nRet = X509_VerifyCert("myreq.p10.txt", "", 0)
If nRet = 0 Then
Debug.Print "Verification is OK"
ElseIf nRet = PKI_X509_VERIFY_FAILURE Then
Debug.Print "Signature is invalid"
Else
Debug.Print "Error: " & nRet & pkiGetLastError()
End If
X509_CertIsValidNow X509_ValidatePath X509_CheckCertInCRL
Generate bytes using an extendable output function (XOF).
Public Declare Function XOF_Bytes Lib "diCrPKI.dll" (ByRef lpOutput As Byte, ByVal nOutBytes As Long, ByRef lpMessage As Byte, ByVal nMsgLen As Long, ByVal nOptions As Long) As Long
nRet = XOF_Bytes(abOutput(0), nOutBytes, abMessage(0), nMsgLen, nOptions)
' Note the "(0)" after the byte array parameters
long __stdcall XOF_Bytes(unsigned char *lpOutput, long nOutBytes, const void *lpMessage, long nMsgLen, long nOptions);
If successful, the return value is the number of bytes in the output; otherwise it returns a negative error code.
Public Function xofBytes (nBytes As Long, lpMessage() As Byte, nOptions As Long) As Byte()
static bvec_t dipki::Xof::Bytes (int numBytes, const bvec_t &message, XofAlg xofalg)
static Xof.bytes(numbytes, msg, xofalg)
The output buffer lpOutput must exist. It will be filled with exactly nOutBytes bytes. Note there is no zero option for nOptions: a valid option flag must be specified.
SHAKE128 and SHAKE256 are described in [FIPS202]. MGF1, despite its name as a Mask Generation Function (MGF), is also an eXtendable Output Function (XOF) using the SHA1/SHA-2 hash functions, and is described in [PKCS1].
Dim strMsgHex As String Dim nOutBits As Long Dim nOutBytes As Long Dim abOut() As Byte Dim abMsg() As Byte Dim nMsgLen As Long Dim strOK As String Dim nRet As Long ' Ref: "SHA-3 XOF Test Vectors for Byte-Oriented Output" ' File `SHAKE256VariableOut.rsp` COUNT = 1244 ' <https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/sha3/shakebytetestvectors.zip> ' Input in hex form strMsgHex = "6ae23f058f0f2264a18cd609acc26dd4dbc00f5c3ee9e13ecaea2bb5a2f0bb6b" nOutBits = 2000 strOK = "b9b92544fb25cfe4ec6fe437d8da2bbe00f7bdaface3de97b8775a44d753c3adca3f7c6f183cc8647e229070439aa9539ae1f8f13470c9d3527fffdeef6c94f9f0520ff0c1ba8b16e16014e1af43ac6d94cb7929188cce9d7b02f81a2746f52ba16988e5f6d93298d778dfe05ea0ef256ae3728643ce3e29c794a0370e9ca6a8bf3e7a41e86770676ac106f7ae79e67027ce7b7b38efe27d253a52b5cb54d6eb4367a87736ed48cb45ef27f42683da140ed3295dfc575d3ea38cfc2a3697cc92864305407369b4abac054e497378dd9fd0c4b352ea3185ce1178b3dc1599df69db29259d4735320c8e7d33e8226620c9a1d22761f1d35bdff79a" ' Convert to byte array form abMsg = cnvBytesFromHexStr(strMsgHex) nMsgLen = UBound(abMsg) + 1 nOutBytes = (nOutBits / 8) ReDim abOut(nOutBytes - 1) nRet = XOF_Bytes(abOut(0), nOutBytes, abMsg(0), nMsgLen, PKI_XOF_SHAKE256) If nRet > 0 Then Debug.Print "OUT=" & cnvHexStrFromBytes(abOut) Debug.Print "OK =" & strOK Else Debug.Print "Error code " & nRet End If
This should result in output as follows:
OUT=B9B92544FB25CFE4EC6FE437D8DA2BBE00F7BDAFACE3DE97B8775A44D753C3ADCA3F7C6F183CC8647E229070439AA9539AE1F8F13470C9D3527FFFDEEF6C94F9F0520FF0C1BA8B16E16014E1AF43AC6D94CB7929188CCE9D7B02F81A2746F52BA16988E5F6D93298D778DFE05EA0EF256AE3728643CE3E29C794A0370E9CA6A8BF3E7A41E86770676AC106F7AE79E67027CE7B7B38EFE27D253A52B5CB54D6EB4367A87736ED48CB45EF27F42683DA140ED3295DFC575D3EA38CFC2A3697CC92864305407369B4ABAC054E497378DD9FD0C4B352EA3185CE1178B3DC1599DF69DB29259D4735320C8E7D33E8226620C9A1D22761F1D35BDFF79A OK =b9b92544fb25cfe4ec6fe437d8da2bbe00f7bdaface3de97b8775a44d753c3adca3f7c6f183cc8647e229070439aa9539ae1f8f13470c9d3527fffdeef6c94f9f0520ff0c1ba8b16e16014e1af43ac6d94cb7929188cce9d7b02f81a2746f52ba16988e5f6d93298d778dfe05ea0ef256ae3728643ce3e29c794a0370e9ca6a8bf3e7a41e86770676ac106f7ae79e67027ce7b7b38efe27d253a52b5cb54d6eb4367a87736ed48cb45ef27f42683da140ed3295dfc575d3ea38cfc2a3697cc92864305407369b4abac054e497378dd9fd0c4b352ea3185ce1178b3dc1599df69db29259d4735320c8e7d33e8226620c9a1d22761f1d35bdff79a
Dim lpMessage() As Byte
Dim lpOut() As Byte
lpMessage = cnvFromHex("6ae23f058f0f2264a18cd609acc26dd4dbc00f5c3ee9e13ecaea2bb5a2f0bb6b")
' Output 2000 bits
lpOut = xofBytes(2000 \ 8, lpMessage, PKI_XOF_SHAKE256)
Debug.Print "OUT=" & cnvToHex(lpOut)
Debug.Print "OK =" & "b9b92544fb25cf...f1d35bdff79a"
' MGF1-SHA-256
lpMessage = cnvFromHex("3b5c056af3ebba70d4c805380420585562b32410a778f558ff951252407647e3")
Debug.Print cnvToHex(lpMessage)
lpOut = xofBytes(34, lpMessage, PKI_XOF_MGF1_SHA256)
Debug.Print "OUT=" & cnvToHex(lpOut)
Debug.Print "OK =" & "5b7eb772aecf04c74af07d9d9c1c1f8d3a90dcda00d5bab1dc28daecdc86eb87611e"
The wrapper functions for VBA/VB6 programmers are now all in basCrPKI.bas.
See Notes on VBA wrapper functions.
Dump details of ASN.1 formatted data to a string.
Public Function asn1TextDumpToString ( _ szFileOrPEMString As String, _ Optional nOptions As Long = 0, _ Optional szDirName As String = "" _ ) As String
PKI_ASN1_NOCOMMENTS PKI_ASN1_ADDLEVELS
"" for default = system TEMP directory.Describe the type of ASN.1 data.
Public Function asn1Type ( _ szFileOrPEMString As String, _ Optional nOptions As Long = 0 _ ) As String
"EC PRIVATE KEY" "OCSP REQUEST" "OCSP RESPONSE" "PKCS1 RSA PRIVATE KEY" "PKCS1 RSA PUBLIC KEY" "PKCS10 CERTIFICATE REQUEST" "PKCS12 PFX" "PKCS7 CERTIFICATE CHAIN" "PKCS7/CMS COMPRESSED DATA" "PKCS7/CMS DATA" "PKCS7/CMS ENVELOPED DATA" "PKCS7/CMS SIGNED DATA" "PKCS8 ENCRYPTED PRIVATE KEY" "PKCS8 PRIVATE KEY INFO" "PUBLIC KEY INFO" "X509 CERTIFICATE" "X509 CRL"
Decrypt data using Authenticated Encryption with Associated Data (AEAD). The authentication tag is expected to be appended to the input ciphertext.
Public Function cipherDecryptAEAD ( _ lpInput() As Byte, _ lpKey() As Byte, _ lpIV() As Byte, _ lpAAD() As Byte, _ nOptions As Long _ ) As Byte()
PKI_AEAD_AES_128_GCM PKI_AEAD_AES_192_GCM PKI_AEAD_AES_256_GCM PKI_AEAD_CHACHA20_POLY1305Add
PKI_IV_PREFIX to expect the IV to be prepended at the start of the input.Decrypts data in a byte array using the specified block cipher algorithm, mode and padding. The key and initialization vector are passed as byte arrays.
Public Function cipherDecryptBytes ( _ lpInput() As Byte, _ lpKey() As Byte, _ lpIV() As Byte, _ szAlgModePad As String, _ Optional nOptions As Long = 0 _ ) As Byte()
"aes128/cbc/pkcs5"
Alg: aes128|aes192|aes256|tdea|3des|desede3 Mode: ecb|cbc|ofb|cfb|ctr|gcm Pad: pkcs5|nopad|oneandzeroes|ansix923|w3c
PKI_IV_PREFIX to expect the IV to be prepended at the start of the input
(ignored for ECB mode).Pkcs5 for ECB and CBC mode and NoPad for all other modes.
GCM mode is only available with AES. The IV must be exactly 12 bytes long for GCM.Decrypt hex-encoded data using the specified block cipher algorithm, mode and padding. The input data, key and initialization vector are all represented as hexadecimal strings.
Public Function cipherDecryptHex ( _ szInputHex As String, _ szKeyHex As String, _ szIvHex As String, _ szAlgModePad As String, _ Optional nOptions As Long = 0 _ ) As String
PKI_IV_PREFIX is used (use "")."aes128/cbc/pkcs5"
Alg: aes128|aes192|aes256|tdea|3des|desede3 Mode: ecb|cbc|ofb|cfb|ctr|gcm Pad: pkcs5|nopad|oneandzeroes|ansix923|w3c
PKI_IV_PREFIX to expect the IV to be prepended before the ciphertext in the input (not applicable for ECB mode).Pkcs5 for ECB and CBC mode and NoPad for all other modes.
GCM mode is only available with AES. The IV must be exactly 12 bytes long for GCM.Encrypt data using Authenticated Encryption with Associated Data (AEAD).
Public Function cipherEncryptAEAD ( _ lpInput() As Byte, _ lpKey() As Byte, _ lpIV() As Byte, _ lpAAD() As Byte, _ nOptions As Long _ ) As Byte()
PKI_AEAD_AES_128_GCM PKI_AEAD_AES_192_GCM PKI_AEAD_AES_256_GCM PKI_AEAD_CHACHA20_POLY1305and optionally add
PKI_IV_PREFIX to prepend the IV (nonce) before the ciphertext in the output.Encrypt data in a byte array using the specified block cipher algorithm, mode and padding. The key and initialization vector are passed as byte arrays.
Public Function cipherEncryptBytes ( _ lpInput() As Byte, _ lpKey() As Byte, _ lpIV() As Byte, _ szAlgModePad As String, _ Optional nOptions As Long = 0 _ ) As Byte()
"aes128/cbc/pkcs5"
Alg: aes128|aes192|aes256|tdea|3des|desede3 Mode: ecb|cbc|ofb|cfb|ctr|gcm Pad: pkcs5|nopad|oneandzeroes|ansix923|w3c
PKI_IV_PREFIX to prepend the IV before the ciphertext in the output
(ignored for ECB mode).Pkcs5 for ECB and CBC mode and NoPad for all other modes.
GCM mode is only available with AES. The IV must be exactly 12 bytes long for GCM.Encrypt hex-encoded data using the specified block cipher algorithm, mode and padding. The key and initialization vector are passed as hex-encoded strings.
Public Function cipherEncryptHex ( _ szInputHex As String, _ szKeyHex As String, _ szIvHex As String, _ szAlgModePad As String, _ Optional nOptions As Long = 0 _ ) As String
"" for ECB mode."aes128/cbc/pkcs5"
Alg: aes128|aes192|aes256|tdea|3des|desede3 Mode: ecb|cbc|ofb|cfb|ctr|gcm Pad: pkcs5|nopad|oneandzeroes|ansix923|w3c
PKI_IV_PREFIX to prepend the IV before the ciphertext in the output
(ignored for ECB mode).Pkcs5 for ECB and CBC mode and NoPad for all other modes.
GCM mode is only available with AES. The IV must be exactly 12 bytes long for GCM.Decrypt a file.
Public Function cipherFileDecrypt ( _ szFileOut As String, _ szFileIn As String, _ lpKey() As Byte, _ lpIV() As Byte, _ szAlgModePad As String, _ Optional nOptions As Long = 0 _ ) As Long
"aes128/cbc/pkcs5"
Alg: aes128|aes192|aes256|tdea|3des|desede3 Mode: ecb|cbc|ofb|cfb|ctr|gcm Pad: pkcs5|nopad|oneandzeroes|ansix923|w3c
PKI_IV_PREFIX to expect the IV before the ciphertext in the input.fileOut and fileIn must not be the same.
GCM mode is only available with AES. The IV must be exactly 12 bytes long for GCM.Encrypt a file.
Public Function cipherFileEncrypt ( _ szFileOut As String, _ szFileIn As String, _ lpKey() As Byte, _ lpIV() As Byte, _ szAlgModePad As String, _ Optional nOptions As Long = 0 _ ) As Long
"aes128/cbc/pkcs5"
Alg: aes128|aes192|aes256|tdea|3des|desede3 Mode: ecb|cbc|ofb|cfb|ctr|gcm Pad: pkcs5|nopad|oneandzeroes|ansix923|w3c
PKI_IV_PREFIX to prepend the IV before the ciphertext in the output
(ignored for ECB mode).fileOut and fileIn must not be the same.
GCM mode is only available with AES. The IV must be exactly 12 bytes long for GCM.Unwraps (decrypts) key material with a key-encryption key.
Public Function cipherKeyUnwrap ( _ lpData() As Byte, _ lpKEK() As Byte, _ nOptions As Long _ ) As Byte()
PKI_BC_AES128 PKI_BC_AES192 PKI_BC_AES256 PKI_BC_3DES
Wraps (encrypts) key material with a key-encryption key.
Public Function cipherKeyWrap ( _ lpData() As Byte, _ lpKEK() As Byte, _ nOptions As Long _ ) As Byte()
PKI_BC_AES128 PKI_BC_AES192 PKI_BC_AES256 PKI_BC_3DES
Extract the message digest from a signed-data CMS object file and verify the signature.
Public Function cmsGetSigDataDigest ( _ szFileIn As String, _ Optional szCertFile As String = "", _ Optional nOptions As Long = 0 _ ) As String
Create a CMS enveloped-data object for one or more recipients.
Public Function cmsMakeEnvData ( _ szFileOut As String, _ szFileIn As String, _ szCertList As String, _ Optional szKeyString As String = "", _ Optional nOptions As Long = 0, _ Optional nCount As Long = 0 _ ) As Long
"type=@pwri" to create a single recipientInfo of the PasswordRecipientInfo (pwri) type;
or set as "type=@kekri,keyid=<string>" to create a single recipientInfo of the KEKRecipientInfo (kekri) type. See Remarks."#x<hex-digits>" to pass a string of arbitrary octet values,
e.g. "#xdeadbeef01" to pass the 5 bytes 0xde,0xad,0xbe,0xef,0x01. Required for pwri and kekri types.PKI_BC_AES128 (default) PKI_BC_AES192 PKI_BC_AES256 PKI_BC_3DES (legacy) PKI_AEAD_AES_128_GCM PKI_AEAD_AES_192_GCM PKI_AEAD_AES_256_GCM PKI_AEAD_CHACHA20_POLY1305To set the key transport scheme (where applicable), use one of
PKI_KT_RSAES_PKCS (default) PKI_KT_RSAES_OAEP PKI_KEM_RSAIf you have selected
PKI_KT_RSAES_OAEP then, optionally, add
PKI_MGF_MGF1SHA1Select one hash algorithm where applicable:
PKI_HASH_SHA1 (default - CAUTION) PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512To set the key derivation function (KDF) (where applicable), add one of:
PKI_KDF_X963 (default for ECDH) PKI_KDF_HKDF PKI_KDF_KDF2 PKI_KDF_KDF3 (default for RSA-KEM)add one key wrap algorithm for the ECDH key agreement scheme or the kekri key encryption algorithm or RSA-KEM (default=match content encryption algorithm):
PKI_KWRAP_3DES (legacy - allowed only if Triple DES is used for content encryption) PKI_KWRAP_AES128 PKI_KWRAP_AES192 PKI_KWRAP_AES256Optionally, add any of the bitflags:
PKI_CMS_FORMAT_BASE64 (default=binary) PKI_CMS_ALT_ALGID PKI_CMS_BIGFILE (binary file to binary file only) PKI_CMS_USE_SKI to use subjectKeyIdentifier (SKI) instead of issuerAndSerialNumber for RecipientInfo
recipientInfo type for each recipient is set automatically depending on the public key found in their certificate.
If RSA, the key transport technique (ktri) will be used; or RSA-KEM if option flag set.
If ECC, then the standard ECDH ephemeral-static key agreement technique (kari) will be used.' Create an enveloped CMS object (ktri type) to Bob using Bob's RSA key... n = cmsMakeEnvData("cms2bob_aes128.p7m", "excontent.txt", "BobRSASignByCarl.cer", "", PKI_BC_AES128 Or PKI_KT_RSAES_OAEP) ' Same but using authenticated encryption and creating an authEnvelopedData object... n = cmsMakeEnvData("cms2bob_aes128auth.p7m", "excontent.txt", "BobRSASignByCarl.cer", "", PKI_AEAD_AES_128_GCM Or PKI_KT_RSAES_OAEP) ' Create an enveloped CMS object (kari type) to Dana using Dana's ECC key... n = cmsMakeEnvData("cms2dana_hkdf.p7m", "excontent.txt", "lamps-dana.encrypt.crt", "", PKI_BC_AES256 Or PKI_HASH_SHA256 Or PKI_KDF_HKDF Or PKI_KWRAP_AES256) ' Create an enveloped CMS object (kekri type) using a previously distributed symmetric key-encryption key (KEK)... n = cmsMakeEnvData("cms_envdata_kekri.p7m", "excontent.txt", "type=@kekri,keyid=ourcommonkey", "#x0123456789ABCDEFF0E1D2C3B4A59687", PKI_BC_AES256 Or PKI_HASH_SHA256 Or PKI_KWRAP_AES128) ' Create an enveloped CMS object (pwri type) using password-based key management... n = cmsMakeEnvData("cms_envdata_pwri.p7m", "excontent.txt", "type=@pwri", "password12345", PKI_BC_AES192)
Create a CMS enveloped-data object from data in a byte array.
Public Function cmsMakeEnvDataFromBytes ( _ szFileOut As String, _ lpInput() As Byte, _ szCertList As String, _ Optional szKeyString As String = "", _ Optional nOptions As Long = 0, _ Optional nCount As Long = 0 _ ) As Long
"type=@pwri" to create a single recipientInfo of the PasswordRecipientInfo (pwri) type;
or set as "type=@kekri,keyid=<string>" to create a single recipientInfo of the KEKRecipientInfo (kekri) type. See Remarks."#x<hex-digits>" to pass a string of arbitrary octet values,
e.g. "#xdeadbeef01" to pass the 5 bytes 0xde,0xad,0xbe,0xef,0x01. Required for pwri and kekri types.Create a CMS enveloped-data object from an ASCII string.
Public Function cmsMakeEnvDataFromString ( _ szFileOut As String, _ szInput As String, _ szCertList As String, _ Optional szKeyString As String = "", _ Optional nOptions As Long = 0, _ Optional nCount As Long = 0 _ ) As Long
"type=@pwri" to create a single recipientInfo of the PasswordRecipientInfo (pwri) type;
or set as "type=@kekri,keyid=<string>" to create a single recipientInfo of the KEKRecipientInfo (kekri) type. See Remarks."#x<hex-digits>" to pass a string of arbitrary octet values,
e.g. "#xdeadbeef01" to pass the 5 bytes 0xde,0xad,0xbe,0xef,0x01. Required for pwri and kekri types.Create a CMS signed-data object from an input data file.
Public Function cmsMakeSigData ( _ szFileOut As String, _ szFileIn As String, _ szCertList As String, _ szPrivateKey As String, _ Optional nOptions As Long = 0 _ ) As Long
PKI_SIG_RSA_SHA1 PKI_SIG_RSA_SHA224 PKI_SIG_RSA_SHA256 PKI_SIG_RSA_SHA384 PKI_SIG_RSA_SHA512 PKI_SIG_RSA_MD5 PKI_SIG_RSA_PSS_SHA1 PKI_SIG_RSA_PSS_SHA224 PKI_SIG_RSA_PSS_SHA256 PKI_SIG_RSA_PSS_SHA384 PKI_SIG_RSA_PSS_SHA512 PKI_SIG_ECDSA_SHA1 PKI_SIG_ECDSA_SHA224 PKI_SIG_ECDSA_SHA256 PKI_SIG_ECDSA_SHA384 PKI_SIG_ECDSA_SHA512 PKI_SIG_ED25519 PKI_SIG_ED448and optionally add any of the following:
PKI_CMS_EXCLUDE_CERTS PKI_CMS_EXCLUDE_DATA PKI_CMS_CERTS_ONLY PKI_CMS_USE_SKI PKI_CMS_INCLUDE_ATTRS PKI_CMS_FORMAT_BASE64 PKI_CMS_NO_OUTER PKI_CMS_ALT_ALGID PKI_CMS_BIGFILE PKI_PSS_SALTLEN_ZERO PKI_MGF_MGF1SHA1 PKI_CMS_ADD_SIGNERIf the
PKI_CMS_INCLUDE_ATTRS option flag is included, optionally add any of the following:
PKI_CMS_ADD_SIGNTIME PKI_CMS_ADD_SMIMECAP PKI_CMS_ADD_SIGNINGCERT PKI_CMS_ADD_ALGPROTECT
Create a CMS signed-data object from data in a byte array.
Public Function cmsMakeSigDataFromBytes ( _ szFileOut As String, _ lpInput() As Byte, _ szCertList As String, _ szPrivateKey As String, _ Optional nOptions As Long = 0 _ ) As Long
PKI_SIG_RSA_SHA1 PKI_SIG_RSA_SHA224 PKI_SIG_RSA_SHA256 PKI_SIG_RSA_SHA384 PKI_SIG_RSA_SHA512 PKI_SIG_RSA_MD5 PKI_SIG_RSA_PSS_SHA1 PKI_SIG_RSA_PSS_SHA224 PKI_SIG_RSA_PSS_SHA256 PKI_SIG_RSA_PSS_SHA384 PKI_SIG_RSA_PSS_SHA512 PKI_SIG_ECDSA_SHA1 PKI_SIG_ECDSA_SHA224 PKI_SIG_ECDSA_SHA256 PKI_SIG_ECDSA_SHA384 PKI_SIG_ECDSA_SHA512 PKI_SIG_ED25519 PKI_SIG_ED448and optionally add any of the following:
PKI_CMS_EXCLUDE_CERTS PKI_CMS_EXCLUDE_DATA PKI_CMS_CERTS_ONLY PKI_CMS_USE_SKI PKI_CMS_INCLUDE_ATTRS PKI_CMS_FORMAT_BASE64 PKI_CMS_NO_OUTER PKI_CMS_ALT_ALGID PKI_CMS_BIGFILE PKI_PSS_SALTLEN_ZERO PKI_MGF_MGF1SHA1 PKI_CMS_ADD_SIGNERIf the
PKI_CMS_INCLUDE_ATTRS option flag is included, optionally add any of the following:
PKI_CMS_ADD_SIGNTIME PKI_CMS_ADD_SMIMECAP PKI_CMS_ADD_SIGNINGCERT PKI_CMS_ADD_ALGPROTECT
Create a CMS signed-data object using a pre-computed signature value.
Public Function cmsMakeSigDataFromSigValue ( _ szFileOut As String, _ lpSigValue() As Byte, _ lpInput() As Byte, _ szCertList As String, _ Optional nOptions As Long = 0 _ ) As Long
PKI_SIG_RSA_SHA1 PKI_SIG_RSA_SHA224 PKI_SIG_RSA_SHA256 PKI_SIG_RSA_SHA384 PKI_SIG_RSA_SHA512 PKI_SIG_RSA_MD5and optionally add any of the following:
PKI_CMS_EXCLUDE_CERTS PKI_CMS_FORMAT_BASE64 PKI_CMS_NO_OUTER PKI_CMS_ALT_ALGID PKI_CMS_PSEUDOSIG
Create a CMS signed-data object from data in a string.
Public Function cmsMakeSigDataFromString ( _ szFileOut As String, _ szDataIn As String, _ szCertList As String, _ szPrivateKey As String, _ Optional nOptions As Long = 0 _ ) As Long
PKI_SIG_RSA_SHA1 PKI_SIG_RSA_SHA224 PKI_SIG_RSA_SHA256 PKI_SIG_RSA_SHA384 PKI_SIG_RSA_SHA512 PKI_SIG_RSA_MD5 PKI_SIG_RSA_PSS_SHA1 PKI_SIG_RSA_PSS_SHA224 PKI_SIG_RSA_PSS_SHA256 PKI_SIG_RSA_PSS_SHA384 PKI_SIG_RSA_PSS_SHA512 PKI_SIG_ECDSA_SHA1 PKI_SIG_ECDSA_SHA224 PKI_SIG_ECDSA_SHA256 PKI_SIG_ECDSA_SHA384 PKI_SIG_ECDSA_SHA512 PKI_SIG_ED25519 PKI_SIG_ED448and optionally add any of the following:
PKI_CMS_EXCLUDE_CERTS PKI_CMS_EXCLUDE_DATA PKI_CMS_CERTS_ONLY PKI_CMS_USE_SKI PKI_CMS_INCLUDE_ATTRS PKI_CMS_FORMAT_BASE64 PKI_CMS_NO_OUTER PKI_CMS_ALT_ALGID PKI_CMS_BIGFILE PKI_PSS_SALTLEN_ZERO PKI_MGF_MGF1SHA1 PKI_CMS_ADD_SIGNERIf the
PKI_CMS_INCLUDE_ATTRS option flag is included, optionally add any of the following:
PKI_CMS_ADD_SIGNTIME PKI_CMS_ADD_SMIMECAP PKI_CMS_ADD_SIGNINGCERT PKI_CMS_ADD_ALGPROTECT
Query a CMS enveloped-data object file for selected information.
Public Function cmsQueryEnvData ( _ szFileIn As String, _ szQuery As String, _ Optional nOptions As Long = 0 _ ) As String
"version" "recipientInfoVersion" "recipientInfoType" "CountOfRecipientInfos" "recipientIssuerName" "recipientSerialNumber" "keyEncryptionAlgorithm" "keyEncryptionFlags" "SizeofEncryptedKey" "encryptedKey" "oaepParams" "kemParams" "keyWrapAlgorithm" "originatorKeyAlgorithm" "originatorPublicKey" "keyid" "ukm" "contentEncryptionAlgorithm" "SizeofEncryptedContent" "encryptedContent" "iv" "HASsubjectKeyIndentifier" "recipientIdentifier"
"recipientInfoVersion/2" to find the version number of the second recipientInfo in the file.Query a CMS signed-data object file for selected information.
Public Function cmsQuerySigData ( _ szFileIn As String, _ szQuery As String, _ Optional nOptions As Long = 0 _ ) As String
"version" "eContentType" "HASeContent" "CountOfCertificates" "CountOfSignerInfos" "CountOfDigestAlgs" "certificate/N" "signerInfoVersion" "digestAlgorithm" "signatureAlgorithm" "HASsignedAttributes" "signingTime" "messageDigest" "pssParams" "HASsigningCertificate" "HASalgorithmProtection" "HASsubjectKeyIndentifier" "signerIdentifier"
"signerInfoVersion/2" to find the version number of the second signerInfo in the file.Read and decrypt a CMS enveloped-data object to a byte array.
Public Function cmsReadEnvDataToBytes ( _ szFileIn As String, _ szCertFile As String, _ szPrivateKey As String, _ Optional nOptions As Long = 0 _ ) As Byte()
Read and decrypt a CMS enveloped-data object to a string.
Public Function cmsReadEnvDataToString ( _ szFileIn As String, _ szCertFile As String, _ szPrivateKey As String, _ Optional nOptions As Long = 0 _ ) As String
cmsReadEnvDataToBytes().Read the content from a CMS signed-data object directly into a byte array.
Public Function cmsReadSigDataToBytes ( _ szFileIn As String, _ Optional nOptions As Long = 0 _ ) As Byte()
Read the content from a CMS signed-data object directly into a string.
Public Function cmsReadSigDataToString ( _ szFileIn As String, _ Optional nOptions As Long = 0 _ ) As String
cmsReadSigDataToBytes().Verify the signature and content of a signed-data CMS object file.
Public Function cmsVerifySigData ( _ szFileIn As String, _ Optional szCertFile As String = "", _ Optional szHexDigest As String = "", _ Optional nOptions As Long = 0 _ ) As Long
PKI_CMS_BIGFILE
Strip any invalid base64 characters from a string.
Public Function cnvB64Filter ( _ szB64 As String _ ) As String
Encode an array of bytes as a base64-encoded string.
Public Function cnvB64StrFromBytes ( _ lpData() As Byte _ ) As String
Re-encode a hexadecimal-encoded binary value as base64.
Public Function cnvB64StrFromHexStr ( _ szHex As String _ ) As String
Encode an ANSI string as a base64-encoded string.
Public Function cnvB64StrFromString ( _ szData As String _ ) As String
Convert 8-bit binary data to equivalent base58-encoded string format.
Public Function cnvBase58FromBytes ( _ lpInput() As Byte _ ) As String
Convert a base58-encoded string to an equivalent array of 8-bit unsigned integers.
Public Function cnvBase58ToBytes ( _ szInput As String _ ) As Byte()
Convert encoding of byte array between UTF-8 and Latin-1.
Public Function cnvByteEncoding ( _ lpInput() As Byte, _ nOptions As Long _ ) As Byte()
PKI_CNV_UTF8_FROM_LATIN1 PKI_CNV_LATIN1_FROM_UTF8
Decode a base64-encoded string as an array of Bytes.
Public Function cnvBytesFromB64Str ( _ szB64 As String _ ) As Byte()
Decode a hexadecimal-encoded string as an array of Bytes.
Public Function cnvBytesFromHexStr ( _ szHex As String _ ) As Byte()
Find length of byte array.
Public Function cnvBytesLen ( _ ab() As Byte _ ) As Long
Dim ab() As Byte Debug.Print cnvBytesLen(ab) ' Expecting 0 ReDim ab(10) ' NB actually 11 elements (0..10) Debug.Print cnvBytesLen(ab) ' 11 ab = vbNullString ' Set to empty array Debug.Print cnvBytesLen(ab) ' 0
Return a substring of bytes of specified length from within a given byte array
Public Function cnvBytesMid ( _ Bytes() As Byte, _ nOffset As Long, _ Optional nBytes As Long = -1 _ ) As Byte()
Check if a byte array contains valid UTF-8 characters.
Public Function cnvCheckUTF8Bytes ( _ lpInput() As Byte _ ) As Long
0 = Not valid UTF-8 1 = Valid UTF-8, all chars are 7-bit ASCII 2 = Valid UTF-8, contains at least one multi-byte character equivalent to 8-bit ANSI 3 = Valid UTF-8, contains at least one multi-byte character that cannot be represented in a single-byte character set
Decodes a base64-encoded string as an array of bytes.
Public Function cnvFromBase64 ( _ strBase64 As String _ ) As Byte()
Decodes a hexadecimal-encoded string as an array of bytes.
Public Function cnvFromHex ( _ strHex As String _ ) As Byte()
Strip any invalid hex characters from a hex string.
Public Function cnvHexFilter ( _ szHex As String _ ) As String
Encode a substring of an array of bytes as a hexadecimal-encoded string.
Public Function cnvHexFromBytesMid ( _ abData() As Byte, _ nOffset As Long, _ nBytes As Long _ ) As String
Debug.Print cnvHexFromBytesMid(cnvBytesFromHexStr("00112233445566"), 3, 2) ' 3344Re-encode a base64-encoded binary value as hexadecimal.
Public Function cnvHexStrFromB64Str ( _ szB64 As String _ ) As String
Encode an array of bytes as a hexadecimal-encoded string.
Public Function cnvHexStrFromBytes ( _ lpData() As Byte _ ) As String
Encode an ANSI string as a hexadecimal-encoded string.
Public Function cnvHexStrFromString ( _ szData As String _ ) As String
Convert UTF-8 encoded array of bytes into a Latin-1 string, if possible.
Public Function cnvLatin1FromUTF8Bytes ( _ lpInput() As Byte _ ) As String
Convert the leftmost four bytes of an array to a 32-bit integer.
Public Function cnvNumFromBytes ( _ lpInput() As Byte, _ Optional nOptions As Long = 0 _ ) As Long
PKI_CNV_BIG_ENDIAN (0) PKI_CNV_LITTLE_ENDIAN
Debug.Print Hex(cnvNumFromBytes(cnvFromHex("DEADBEEF")))
'DEADBEEF
Debug.Print cnvNumFromBytes(cnvFromHex("DEADBEEF"))
'-559038737Convert a 32-bit integer to an array of 4 bytes.
Public Function cnvNumToBytes ( _ nNumber As Long, _ Optional nOptions As Long = 0 _ ) As Byte()
PKI_CNV_BIG_ENDIAN (0) PKI_CNV_LITTLE_ENDIAN
Debug.Print cnvToHex(cnvNumToBytes(&HDEADBEEF, PKI_CNV_LITTLE_ENDIAN))
'EFBEADDEReverse the order of a byte array.
Public Function cnvReverseBytes ( _ lpInput() As Byte _ ) As Byte()
Debug.Print cnvToHex(cnvReverseBytes(cnvFromHex("DEADBEEF")))
'EFBEADDEDecode a hexadecimal-encoded string as an ANSI string.
Public Function cnvStringFromHexStr ( _ ByVal szHex As String _ ) As String
Encodes an array of bytes as a base64-encoded string.
Public Function cnvToBase64 ( _ lpData() As Byte _ ) As String
Encodes an array of bytes as a hexadecimal-encoded string.
Public Function cnvToHex ( _ lpData() As Byte _ ) As String
Convert a string of 8-bit Latin-1 (ISO-8859-1) characters into a UTF-8 encoded array of bytes.
Public Function cnvUTF8BytesFromLatin1 ( _ szInput As String _ ) As Byte()
Compress data using zlib compression.
Public Function comprCompress ( _ lpInput() As Byte, _ Optional nOptions As Long = 0 _ ) As Byte()
Uncompress data using zlib compression.
Public Function comprUncompress ( _ lpInput() As Byte, _ Optional nOptions As Long = 0 _ ) As Byte()
Compute EC Diffie-Hellman (ECDH) shared secret.
Public Function eccDHSharedSecret ( _ szIntPrivateKey As String, _ szIntPublicKey As String, _ Optional nOptions As Long = 0 _ ) As Byte()
Compute the hash code of an "internal" ECC public or private key string.
Public Function eccKeyHashCode ( _ szIntKeyString As String _ ) As Long
Generate an EC public/private key pair and save as two key files.
Public Function eccMakeKeys ( _ szPubKeyFile As String, _ szPriKeyFile As String, _ szCurveName As String, _ szPassword As String, _ Optional szParams As String = "", _ Optional nOptions As Long = 0 _ ) As Long
PKI_PBE_SHA_3DES (0) for "pbeWithSHAAnd3-KeyTripleDES-CBC" from PKCS12 (default) PKI_PBE_PBKDF2_DESEDE3 for PBKDF2 using des-EDE3-CBC PKI_PBE_PBKDF2_AES128 for PBKDF2 using aes128-CBC PKI_PBE_PBKDF2_AES192 for PBKDF2 using aes192-CBC PKI_PBE_PBKDF2_AES256 for PBKDF2 using aes256-CBCplus optionally to output in textual PEM format [default format=DER binary]
PKI_KEY_FORMAT_PEM
szParams are:"count=5000;" [default=2048]."prf=hmacWithSHA256;" [default=hmacWithSHA1]."rngseed=pqrrr1234xyz;".{hmacWithSHA1|hmacWithSHA224|hmacWithSHA256|hmacWithSHA384|hmacWithSHA512}.' Create an ECC key pair using defaults r = eccMakeKeys("myeccP256.pub", "myeccP256.p8e", "Secp256r1", "password") ' Same but using different curve, stronger security and in PEM format r = eccMakeKeys("myeccBP256r1.pub", "myeccBP256r1.p8e", "brainpoolP256r1", "password1", "count=6000;prf=hmacWithSHA256", PKI_PBE_PBKDF2_AES128 Or PKI_KEY_FORMAT_PEM)
Convert an internal EC private key string into an internal EC public key string.
Public Function eccPublicKeyFromPrivate ( _ szIntKeyString As String, _ Optional nOptions As Long = 0 _ ) As String
Query an EC key string for selected information.
Public Function eccQueryKey ( _ szIntKeyString As String, _ szQuery As String, _ Optional nOptions As Long = 0 _ ) As String
curveName keyBits isPrivate privateKey publicKey
Read an EC key from its hexadecimal representation.
Public Function eccReadKeyByCurve ( _ szHexKey As String, _ szCurveName As String, _ Optional nOptions As Long = 0 _ ) As String
PKI_ECC_PRIVATE_KEY or PKI_ECC_PUBLIC_KEY to indicate that the key value
represents a private or public key, respectively. Otherwise, nOptions is ignored.Read an EC private key from a file into an internal key string.
Public Function eccReadPrivateKey ( _ szKeyFileOrString As String, _ Optional szPassword As String = "", _ Optional nOptions As Long = 0 _ ) As String
"".Read an EC private key from a file into an internal key string.
Public Function eccReadPublicKey ( _ szKeyFileOrString As String, _ Optional nOptions As Long = 0 _ ) As String
Save an internal EC private key string to an encrypted key file.
Public Function eccSaveEncKey ( _ szOutputFile As String, _ szKeyStr As String, _ szPassword As String, _ Optional szParams As String = "", _ Optional nOptions As Long = 0 _ ) As Long
PKI_PBE_SHA_3DES (0) for "pbeWithSHAAnd3-KeyTripleDES-CBC" from PKCS12 (default) PKI_PBE_PBKDF2_DESEDE3 for PBKDF2 using des-EDE3-CBC PKI_PBE_PBKDF2_AES128 for PBKDF2 using aes128-CBC PKI_PBE_PBKDF2_AES192 for PBKDF2 using aes192-CBC PKI_PBE_PBKDF2_AES256 for PBKDF2 using aes256-CBCplus optionally add the following to output in textual PEM format [default format=DER binary]
PKI_KEY_FORMAT_PEM
szParams are:"count=5000;" [default=2048]."prf=hmacWithSHA256;" [default=hmacWithSHA1].{hmacWithSHA1|hmacWithSHA224|hmacWithSHA256|hmacWithSHA384|hmacWithSHA512}.Save an internal EC key string to a key file.
Public Function eccSaveKey ( _ szOutputFile As String, _ szKeyStr As String, _ Optional nOptions As Long = 0 _ ) As Long
PKI_DEFAULT (0) to save the key in the default format. PKI_KEY_TYPE_PKCS8 to save a NIST/SEC curve private key in PKCS#8 format.and optionally add any of
PKI_KEY_FORMAT_PEM to save the key file in PEM form (default is binary DER-encoded format). PKI_KEY_LEGACY to save a safe key in "legacy" PKCS#8 v1 format (default is v2 OneAsymmetricKey).
PKI_KEY_TYPE_PKCS8 option to save in PKCS#8 PrivateKeyInfo format [RFC5208].
Safe curve private keys (X25519, Ed25519, X448 and Ed448) are always saved in PKCS#8 v2
OneAsymmetricKey format including the public key [RFC5958]. Add the option PKI_KEY_LEGACY
to save in older PKCS#8 v1 PrivateKeyInfo format [RFC5208] excluding the public key.
To save a private key in encrypted form, use eccSaveEncKey.Return an error message string for the last error.
Public Function errFormatErrorMessage ( _ Optional nErrCode As Long = 0, _ Optional szMsg As String = "" _ ) As String
Debug.Print errFormatErrorMessage(11) Error (11): Parameter out of range (OUT_OF_RANGE_ERROR) Debug.Print errFormatErrorMessage(11, "User message!") ERROR: User message! (11): Value out of range (OUT_OF_RANGE_ERROR)
Compute hash digest in byte format of byte input.
Public Function hashBytes ( _ lpMessage() As Byte, _ nOptions As Long _ ) As Byte()
PKI_HASH_SHA1 PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512 PKI_HASH_SHA3_224 PKI_HASH_SHA3_256 PKI_HASH_SHA3_384 PKI_HASH_SHA3_512 PKI_HASH_MD5 PKI_HASH_MD2 PKI_HASH_RMD160 PKI_HASH_BTC160and optionally add
PKI_HASH_DOUBLE to compute a double hash, HASH(HASH(m)).Compute hash digest in byte format of a file.
Public Function hashFile ( _ szFileName As String, _ nOptions As Long _ ) As Byte()
PKI_HASH_SHA1 PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512 PKI_HASH_SHA3_224 PKI_HASH_SHA3_256 PKI_HASH_SHA3_384 PKI_HASH_SHA3_512 PKI_HASH_MD5 PKI_HASH_MD2 PKI_HASH_RMD160 PKI_HASH_BTC160and optionally add
PKI_HASH_DOUBLE to compute a double hash, HASH(HASH(m)).
Add PKI_HASH_MODE_TEXT to hash in "text" mode instead of default "binary" mode.Compute hash digest in hex format of byte input.
Public Function hashHexFromBytes ( _ lpMessage() As Byte, _ nOptions As Long _ ) As String
PKI_HASH_SHA1 PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512 PKI_HASH_SHA3_224 PKI_HASH_SHA3_256 PKI_HASH_SHA3_384 PKI_HASH_SHA3_512 PKI_HASH_MD5 PKI_HASH_MD2 PKI_HASH_RMD160 PKI_HASH_BTC160and optionally add
PKI_HASH_DOUBLE to compute a double hash, HASH(HASH(m)).Compute hash digest in hex format of a file.
Public Function hashHexFromFile ( _ szFileName As String, _ nOptions As Long _ ) As String
PKI_HASH_SHA1 PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512 PKI_HASH_SHA3_224 PKI_HASH_SHA3_256 PKI_HASH_SHA3_384 PKI_HASH_SHA3_512 PKI_HASH_MD5 PKI_HASH_MD2 PKI_HASH_RMD160 PKI_HASH_BTC160and optionally add
PKI_HASH_DOUBLE to compute a double hash, HASH(HASH(m)).
Add PKI_HASH_MODE_TEXT to hash in "text" mode instead of default "binary" mode.Compute hash digest in hex-encoded format from hex-encoded input.
Public Function hashHexFromHex ( _ szMsgHex As String, _ nOptions As Long _ ) As String
PKI_HASH_SHA1 PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512 PKI_HASH_SHA3_224 PKI_HASH_SHA3_256 PKI_HASH_SHA3_384 PKI_HASH_SHA3_512 PKI_HASH_MD5 PKI_HASH_MD2 PKI_HASH_RMD160 PKI_HASH_BTC160and optionally add
PKI_HASH_DOUBLE to compute a double hash, HASH(HASH(m)).Return length of message digest output in bytes.
Public Function hashLength ( _ nAlgId As Long _ ) As Long
PKI_HASH_* or PKI_HMAC_*, for example:
PKI_HASH_SHA1 PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512 PKI_HASH_SHA3_224 PKI_HASH_SHA3_256 PKI_HASH_SHA3_384 PKI_HASH_SHA3_512 PKI_HASH_MD5 PKI_HASH_MD2 PKI_HASH_RMD160 PKI_HASH_BTC160
Debug.Print hashLength(PKI_HASH_SHA512) 64
Compute hash-based message authentication code (HMAC) as a byte array from byte data.
Public Function hmacBytes ( _ lpMessage() As Byte, _ lpKey() As Byte, _ nOptions As Long _ ) As Byte()
PKI_HMAC_SHA1 PKI_HMAC_SHA224 PKI_HMAC_SHA256 PKI_HMAC_SHA384 PKI_HMAC_SHA512 PKI_HMAC_SHA3_224 PKI_HMAC_SHA3_256 PKI_HMAC_SHA3_384 PKI_HMAC_SHA3_512 PKI_HMAC_MD5
Compute hash-based message authentication code (HMAC) in hexadecimal format from byte data.
Public Function hmacHexFromBytes ( _ lpMessage() As Byte, _ lpKey() As Byte, _ nOptions As Long _ ) As String
PKI_HMAC_SHA1 PKI_HMAC_SHA224 PKI_HMAC_SHA256 PKI_HMAC_SHA384 PKI_HMAC_SHA512 PKI_HMAC_SHA3_224 PKI_HMAC_SHA3_256 PKI_HMAC_SHA3_384 PKI_HMAC_SHA3_512 PKI_HMAC_MD5
Compute hash-based message authentication code (HMAC) in hexadecimal format from data in hexadecimal-encoded strings.
Public Function hmacHexFromHex ( _ szMsgHex As String, _ szKeyHex As String, _ nOptions As Long _ ) As String
PKI_HMAC_SHA1 PKI_HMAC_SHA224 PKI_HMAC_SHA256 PKI_HMAC_SHA384 PKI_HMAC_SHA512 PKI_HMAC_SHA3_224 PKI_HMAC_SHA3_256 PKI_HMAC_SHA3_384 PKI_HMAC_SHA3_512 PKI_HMAC_MD5
Derive an EC private key in a deterministic manner from input keying material using the DeriveKeyPair algorithm in RFC9180.
Public Function hpkeDerivePrivateKey ( _ lpIkm() As Byte, _ szCurveName As String, _ Optional nOptions As Long = 0 _ ) As String
"P-256" | "P-384" | "P-521" | "X25519" | "X448"
PKI_ENCODE_HEX to output the private key in serialized hex form.PKI_ENCODE_HEX then the key is output in serialized hexadecimal form in the same manner
as the test vectors in [RFC9180] (without the clamping).Compute the output of the LabeledExpand function as defined in RFC9180.
Public Function hpkeLabeledExpand ( _ nBytes As Long, _ lpPrk() As Byte, _ szLabel As String, _ lpInfo() As Byte, _ szCurveName As String, _ Optional nOptions As Long = 0 _ ) As Byte()
"P-256" | "P-384" | "P-521" | "X25519" | "X448"
PKI_AEAD_AES_128_GCM PKI_AEAD_AES_256_GCM PKI_AEAD_CHACHA20_POLY1305
Compute the output of the LabeledExtract function as defined in RFC9180.
Public Function hpkeLabeledExtract ( _ lpSalt() As Byte, _ szLabel As String, _ lpIkm() As Byte, _ szCurveName As String, _ Optional nOptions As Long = 0 _ ) As Byte()
"P-256" | "P-384" | "P-521" | "X25519" | "X448"
PKI_AEAD_AES_128_GCM PKI_AEAD_AES_256_GCM PKI_AEAD_CHACHA20_POLY1305
Generate a key-encryption key (KEK) from input keying material (IKM) using a key derivation function (KDF).
Public Function kdfBytes ( _ nKekBytes As Long, _ lpIkm() As Byte, _ lpInfo() As Byte, _ Optional nOptions As Long = 0, _ Optional szParams As String = "" _ ) As Byte()
PKI_KDF_X963 (default) PKI_KDF_HKDF PKI_KDF_KDF2 PKI_KDF_KDF3and select one hash algorithm to use with the key derivation function:
PKI_HASH_SHA1 (default) PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512
"" for defaults.
Use salt=<hex-digits> to set the optional salt parameter for the HKDF algorithm encoded in hex,
e.g. "salt=606162636465666768696a6b6c6d6e6f;".PKI_KDF_X963 uses the ANSI-X9.63-KDF key derivation function.
PKI_KDF_HKDF uses the HMAC-based Key Derivation Function (HKDF) from RFC 5869.Dim lpKEK() As Byte Dim lpZZ() As Byte Dim lpInfo() As Byte ' ansx963_2001.rsp CAVS 12.0 'ANS X9.63-2001' information for sample lpZZ = cnvFromHex("96c05619d56c328ab95fe84b18264b08725b85e33fd34f08") lpKEK = kdfBytes(128 \ 8, lpZZ, lpInfo, PKI_HASH_SHA256) Debug.Print "KEK = " & cnvToHex(lpKEK) Debug.Print "OK = 443024c3dae66b95e6f5670601558f71" ' [RFC 5869] A.1. Test Case 1 Basic test case with SHA-256 lpZZ = cnvFromHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") lpInfo = cnvFromHex("f0f1f2f3f4f5f6f7f8f9") lpKEK = kdfBytes(42, lpZZ, lpInfo, PKI_KDF_HKDF Or PKI_HASH_SHA256, "salt=000102030405060708090a0b0c") Debug.Print "KEK = " & cnvToHex(lpKEK) Debug.Print "OK = 3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"
Generate a key-encryption key (KEK) for ECDH key exchange in a CMS EnvelopedData object.
Public Function kdfForCms ( _ lpZZ() As Byte, _ lpUkm() As Byte, _ Optional nOptions As Long = 0 _ ) As Byte()
PKI_KDF_X963 (default) PKI_KDF_HKDFand select one hash algorithm to use with the key derivation function:
PKI_HASH_SHA1 (default) PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512and select one key wrap algorithm (required, no default):
PKI_KWRAP_3DES PKI_KWRAP_AES128 PKI_KWRAP_AES192 PKI_KWRAP_AES256
Dim lpKEK() As Byte
Dim lpZZ() As Byte
Dim lpUkm() As Byte
lpZZ = cnvFromHex("160E3F5588C6FB4E9CEE8BC3C1C5000AB86396468C3D1CAEC0CB6E21536B5513")
lpKEK = kdfForCms(lpZZ, lpUkm, PKI_KWRAP_AES128 Or PKI_KDF_X963 Or PKI_HASH_SHA1)
Debug.Print "KEK = " & cnvToHex(lpKEK)
Debug.Print "OK = 04D616C654CDF62BB186A5A088B60FB5"Create an Online Certification Status Protocol (OCSP) request as a base64 string.
Public Function ocspMakeRequest ( _ szIssuerCert As String, _ szCertFileOrSerialNum As String, _ nOptions As Long, _ Optional szExtensions As String = "" _ ) As String
#x.PKI_HASH_SHA1 PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512 PKI_HASH_MD5
Read a response to an Online Certification Status Protocol (OCSP) request and outputs the main results in text form.
Public Function ocspReadResponse ( _ szResponseFile As String, _ Optional szIssuerCert As String = "", _ Optional nOptions As Long = 0, _ Optional szExtensions As String = "" _ ) As String
Creates an input block suitably padded for encryption by a block cipher in ECB or CBC mode.
Public Function padBytesBlock ( _ lpInput() As Byte, _ nBlkLen As Long, _ Optional nOptions As Long = 0 _ ) As Byte()
PKI_PAD_1ZERO PKI_PAD_AX923 PKI_PAD_W3C
Creates a hex-encoded input block suitably padded for encryption by a block cipher in ECB or CBC mode.
Public Function padHexBlock ( _ szInput As String, _ nBlkLen As Long, _ Optional nOptions As Long = 0 _ ) As String
PKI_PAD_1ZERO PKI_PAD_AX923 PKI_PAD_W3C
Removes the padding from an encryption block.
Public Function padUnpadBytes ( _ lpInput() As Byte, _ nBlkLen As Long, _ Optional nOptions As Long = 0 _ ) As Byte()
PKI_PAD_1ZERO PKI_PAD_AX923 PKI_PAD_W3C
Removes the padding from a hex-encoded encryption block.
Public Function padUnpadHex ( _ szInput As String, _ nBlkLen As Long, _ Optional nOptions As Long = 0 _ ) As String
PKI_PAD_1ZERO PKI_PAD_AX923 PKI_PAD_W3C
Derives a key of any length from a password using the PBKDF2 algorithm from PKCS#5 v2.1.
Public Function pbeKdf2 ( _ dkBytes As Long, _ lpPwd() As Byte, _ lpSalt() As Byte, _ nCount As Long, _ Optional nOptions As Long = 0 _ ) As Byte()
PKI_HMAC_SHA1 PKI_HMAC_SHA224 PKI_HMAC_SHA256 PKI_HMAC_SHA384 PKI_HMAC_SHA512 PKI_HMAC_MD5
Derives a hex-encoded key of any length from a password using the PBKDF2 algorithm from PKCS#5 v2.1. The salt and derived key are encoded in hexadecimal.
Public Function pbeKdf2Hex ( _ dkBytes As Long, _ szPwd As String, _ szSaltHex As String, _ nCount As Long, _ Optional nOptions As Long = 0 _ ) As String
PKI_HMAC_SHA1 PKI_HMAC_SHA224 PKI_HMAC_SHA256 PKI_HMAC_SHA384 PKI_HMAC_SHA512 PKI_HMAC_MD5
Derives a key of any length from a password using the SCRYPT algorithm from RFC7914.
Public Function pbeScrypt ( _ dkBytes As Long, _ lpPwd() As Byte, _ lpSalt() As Byte, _ nParamN As Long, _ nParamR As Long, _ nParamP As Long, _ Optional nOptions As Long = 0 _ ) As Byte()
N ("costParameter"), a number greater than one and a power of 2.r ("blockSize").p ("parallelizationParameter").Derives a hex-encoded key of any length from a password using the SCRYPT algorithm from RFC7914. The salt and derived key are encoded in hexadecimal.
Public Function pbeScryptHex ( _ dkBytes As Long, _ szPwd As String, _ szSaltHex As String, _ nParamN As Long, _ nParamR As Long, _ nParamP As Long, _ Optional nOptions As Long = 0 _ ) As String
N ("costParameter"), a number greater than one and a power of 2.r ("blockSize").p ("parallelizationParameter").
Debug.Print pbeScryptHex(64, "password", "4E61436C", 1024, 8, 16)
' FDBABE1C9D3472007856E7190D01E9FE7C6AD7CBC8237830E77376634B3731622EAF30D92E22A3886FF109279D9830DAC727AFB94A83EE6D8360CBDFA2CC0640Create a PFX (PKCS-12) file from an X.509 certificate and (optional) encrypted private key file.
Public Function pfxMakeFile ( _ szFileOut As String, _ szCertList As String, _ Optional szKeyFile As String = "", _ Optional szPassword As String = "", _ Optional szFriendlyName As String = "", _ Optional nOptions As Long = 0 _ ) As Long
PKI_PFX_CLONE_KEY PKI_PFX_PLAIN_CERT PKI_PFX_STRONG_CERT PKI_PFX_AES256_SHA256 PKI_PFX_DOUBLE_ENCRYPT PKI_KEY_FORMAT_PEM PKI_PFX_ALT_FORMAT
Get date and time the CryptoSys PKI DLL module was last compiled.
Public Function pkiCompileTime() As String
Returns the error code of the error that occurred when calling the last function.
Public Function pkiErrorCode() As Long
Get error message associated with a given error code.
Public Function pkiErrorLookup ( _ nErrCode As Long _ ) As String
Get last error message set by previous function.
Public Function pkiLastError() As String
Returns the ASCII value of the licence type.
Public Function pkiLicenceType ( _ Optional nOptions As Long = 0 _ ) As String
D=Developer T=Trial.Get additional information about the core DLL module.
Public Function pkiModuleInfo ( _ Optional nOptions As Long = 0 _ ) As String
Get path name of the current process's module.
Public Function pkiModuleName ( _ Optional nOptions As Long = 0 _ ) As String
Debug.Print pkiModuleName() C:\WINDOWS\SYSTEM32\diCrPKI.dll
Get platform the core DLL was compiled for.
Public Function pkiPlatform() As String
"Win32" or "X64".Get version number of native core DLL.
Public Function pkiVersion() As Long
Major*100*100 + Minor*100 + Revision. For example, version 6.1.2 would return 60102.Generate output bytes using a pseudorandom function (PRF).
Public Function prfBytes ( _ nBytes As Long, _ lpMessage() As Byte, _ lpKey() As Byte, _ nOptions As Long, _ Optional szCustom As String = "" _ ) As Byte()
PKI_KMAC_128 PKI_KMAC_256
Prompt for a password in a dialog box.
Public Function pwdPrompt ( _ Optional szCaption As String = "", _ Optional szPrompt As String = "" _ ) As String
"" if user cancels.Generate random bytes.
Public Function rngBytes ( _ nBytes As Long _ ) As Byte()
Generate a random 36-character Global Unique IDentifier (GUID) string.
Public Function rngGuid() As String
Debug.Print rngGuid() ba849198-168e-4632-a865-2761c9c8dd37
Initialize the RNG generator using a seed file.
Public Function rngInitialize ( _ szSeedFile As String _ ) As Long
Query and initialize the RNG generator using Intel(R) DRNG, if available.
Public Function rngInitializeEx ( _ Optional nOptions As Long = 0 _ ) As Long
PKI_RNG_NO_INTEL_DRNG to explicitly turn off support.Decode an EME or EMSA encoded message block according to PKCS#1.
Public Function rsaDecodeMsg ( _ lpInput() As Byte, _ nOptions As Long _ ) As Byte()
PKI_EME_PKCSV1_5 PKI_EME_OAEP PKI_EMSIG_PKCSV1_5If you have selected
PKI_EMSIG_PKCSV1_5, then you can add
PKI_EMSIG_DIGINFO to decode an 'Encoded Message for Signature' block and output the whole DigestInfo data instead of just the message digest.
PKI_HASH_SHA1 PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512and optionally add
PKI_MGF_MGF1SHA1 to force the MGF hash function to be SHA-1 (default = same as encoding hash function set above).
PKI_EMSIG_ISO9796 to use the ISO9796-1 encoding for a signature.Decrypt a message encrypted using an RSA encryption scheme.
Public Function rsaDecrypt ( _ lpInput() As Byte, _ szPrivateKeyFile As String, _ szPassword As String, _ nOptions As Long, _ Optional szParameters As String = "" _ ) As Byte()
"" if password is not required.PKI_EME_PKCSV1_5 (0 default) PKI_EME_OAEP
Encode an EME or EMSA encoded message block according to PKCS#1.
Public Function rsaEncodeMsg ( _ nBlockLen As Long, _ lpInput() As Byte, _ nOptions As Long _ ) As Byte()
PKI_EME_PKCSV1_5 PKI_EME_OAEP PKI_EMSIG_PKCSV1_5If you have selected
PKI_EMSIG_PKCSV1_5, then add one of these options to set the hash function for the signature message digest:
PKI_HASH_SHA1 PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512 PKI_HASH_MD5 PKI_HASH_MD2and optionally add
PKI_EMSIG_DIGESTONLY as a flag to pass the message digest only as input to-be-signed (default = pass entire message).
PKI_HASH_SHA1 PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512and optionally add
PKI_MGF_MGF1SHA1 to force the MGF hash function to be SHA-1 (default = same as encoding hash function set above).
PKI_EMSIG_ISO9796 to use the ISO9796-1 encoding for a signature.Encrypt a short message using RSA encryption.
Public Function rsaEncrypt ( _ lpInput() As Byte, _ szPublicKeyFile As String, _ Optional nOptions As Long = 0, _ Optional szParameters As String = "" _ ) As Byte()
PKI_EME_PKCSV1_5 (0 default) PKI_EME_OAEPIf you have selected
PKI_EME_OAEP, then add one of these options to set the hash function for EME-OAEP encoding:
PKI_HASH_SHA1 PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512and, optionally, add
PKI_MGF_MGF1SHA1 to force the MGF hash function to be SHA-1 (default = same as encoding hash function set above).Create an RSA key string in internal format from an XML string.
Public Function rsaFromXMLString ( _ szXmlString As String, _ Optional nOptions As Long = 0 _ ) As String
PKI_XML_EXCLPRIVATE to exclude the private key even if present, or
PKI_XML_REQPRIVATE to require the private key to exist in the XML input or fail.Get number of significant bits in RSA key modulus.
Public Function rsaKeyBits ( _ szKeyString As String _ ) As Long
Get number of bytes (octets) in RSA key modulus.
Public Function rsaKeyBytes ( _ szKeyString As String _ ) As Long
Extract a base64-encoded RSA key value from internal key string.
Public Function rsaKeyValue ( _ szKeyString As String, _ szFieldName As String, _ Optional nOptions As Long = 0 _ ) As String
"Modulus" or "Exponent".Generate an RSA public/private key pair and save as two key files.
Public Function rsaMakeKeys ( _ szPubKeyFile As String, _ szPriKeyFile As String, _ szPassword As String, _ nBits As Long, _ Optional nExpFermat As Long = PKI_RSAEXP_EQ_65537, _ Optional szParams As String = "", _ Optional nOptions As Long = 0 _ ) As Long
PKI_PBE_SHA_3DES (0) for "pbeWithSHAAnd3-KeyTripleDES-CBC" from PKCS12 (default) PKI_PBE_PBKDF2_DESEDE3 for PBKDF2 using des-EDE3-CBC PKI_PBE_PBKDF2_AES128 for PBKDF2 using aes128-CBC PKI_PBE_PBKDF2_AES192 for PBKDF2 using aes192-CBC PKI_PBE_PBKDF2_AES256 for PBKDF2 using aes256-CBCplus optionally one of the following to output in textual PEM format [default format=DER binary]
PKI_KEY_FORMAT_PEM PKI_KEY_FORMAT_SSLand, optionally, add
PKI_KEYGEN_INDICATE to indicate progress in a console window.szParams are:"count=5000;" [default=2048]."prf=hmacWithSHA256;" [default=hmacWithSHA1]."rngseed=pqrrr1234xyz;".{hmacWithSHA1|hmacWithSHA224|hmacWithSHA256|hmacWithSHA384|hmacWithSHA512}.' Create a 2048-bit RSA key pair using defaults r = rsaMakeKeys("myrsa2048.pub", "myrsa2048.p8e", "password", 2048) ' Same but using stronger security and in PEM format r = rsaMakeKeys("myrsa2048ex.pub", "myrsa2048ex.p8e", "password1", 2048,,"count=6000;prf=hmacWithSHA256", PKI_PBE_PBKDF2_AES128 Or PKI_KEY_FORMAT_PEM)
Convert an internal RSA private key string into an internal public key string.
Public Function rsaPublicKeyFromPrivate ( _ szKeyString As String, _ Optional nOptions As Long = 0 _ ) As String
Carry out RSA transformation on raw data using private key.
Public Function rsaRawPrivate ( _ lpData() As Byte, _ szPrivateKey As String, _ Optional nOptions As Long = 0 _ ) As Byte()
RSA_KeyBytes() to find this).Carry out RSA transformation on raw data using public key.
Public Function rsaRawPublic ( _ lpData() As Byte, _ szPublicKey As String, _ Optional nOptions As Long = 0 _ ) As Byte()
RSA_KeyBytes() to find this).Read private key from a file or string containing a key into an "internal" public key string.
Public Function rsaReadAnyPrivateKey ( _ szKeyFileOrString As String, _ Optional szPassword As String = "", _ Optional nOptions As Long = 0 _ ) As String
"" if not.Read public key from a file or string containing a key into an "internal" public key string.
Public Function rsaReadAnyPublicKey ( _ szKeyFileOrString As String, _ Optional nOptions As Long = 0 _ ) As String
Read private key from a file or string containing a key into an "internal" public key string.
Public Function rsaReadPrivateKey ( _ szKeyFileOrString As String, _ Optional szPassword As String = "", _ Optional nOptions As Long = 0 _ ) As String
"" if not.Read public key from a file or string containing a key into an "internal" public key string.
Public Function rsaReadPublicKey ( _ szKeyFileOrString As String, _ Optional nOptions As Long = 0 _ ) As String
Save an internal RSA key string to an encrypted key file.
Public Function rsaSaveEncKey ( _ szOutputFile As String, _ szKeyStr As String, _ szPassword As String, _ Optional szParams As String = "", _ Optional nOptions As Long = 0 _ ) As Long
PKI_PBE_SHA_3DES (0) for "pbeWithSHAAnd3-KeyTripleDES-CBC" from PKCS12 (default) PKI_PBE_PBKDF2_DESEDE3 for PBKDF2 using des-EDE3-CBC PKI_PBE_PBKDF2_AES128 for PBKDF2 using aes128-CBC PKI_PBE_PBKDF2_AES192 for PBKDF2 using aes192-CBC PKI_PBE_PBKDF2_AES256 for PBKDF2 using aes256-CBCplus optionally one of the following to output in textual PEM format [default format=DER binary]
PKI_KEY_FORMAT_PEM PKI_KEY_FORMAT_SSL
szParams are:"count=5000;" [default=2048]."prf=hmacWithSHA256;" [default=hmacWithSHA1].{hmacWithSHA1|hmacWithSHA224|hmacWithSHA256|hmacWithSHA384|hmacWithSHA512}.Save an internal RSA key string to a key file.
Public Function rsaSaveKey ( _ szOutputFile As String, _ szKeyStr As String, _ Optional nOptions As Long = 0 _ ) As Long
PKI_KEY_FORMAT_PEM PKI_KEY_FORMAT_SSL
Create an XML string representation of an RSA internal key string.
Public Function rsaToXMLString ( _ szKeyString As String, _ Optional nOptions As Long = 0 _ ) As String
RSAKeyValue for public key and RSAKeyPair for private key), or select and combine:
PKI_XML_RSAKEYVALUE to force private key output as .NET-compatible RSAKeyValue format (instead of W3C RSAKeyPair)
PKI_XML_EXCLPRIVATE to exclude the private key (use to get a public key RSAKeyValue from a private key)
PKI_XML_HEXBINARY to output with data in non-conforming (but convenient) hexBinary format.Create an XML string representation of an RSA internal key string with option to add a namespace prefix.
Public Function rsaToXMLStringEx ( _ szKeyString As String, _ szPrefix As String, _ Optional nOptions As Long = 0 _ ) As String
"ds".RSAKeyValue for public key and RSAKeyPair for private key), or select and combine:
PKI_XML_RSAKEYVALUE to force private key output as .NET-compatible RSAKeyValue format (instead of W3C RSAKeyPair)
PKI_XML_EXCLPRIVATE to exclude the private key (use to get a public key RSAKeyValue from a private key)
PKI_XML_HEXBINARY to output with data in non-conforming (but convenient) hexBinary format.<ds:RSAKeyValue>.Compute a signature value over data in a byte array.
Public Function sigSignData ( _ lpData() As Byte, _ szKeyFile As String, _ szPassword As String, _ szAlgName As String, _ Optional nOptions As Long = 0 _ ) As String
"" if not required."sha1WithRSAEncryption" "sha224WithRSAEncryption" "sha256WithRSAEncryption" "sha384WithRSAEncryption" "sha512WithRSAEncryption" "md5WithRSAEncryption" "ecdsaWithSHA1" "ecdsaWithSHA224" "ecdsaWithSHA256" "ecdsaWithSHA384" "ecdsaWithSHA512" "RSA-PSS-SHA1" "RSA-PSS-SHA224" "RSA-PSS-SHA256" "RSA-PSS-SHA384" "RSA-PSS-SHA512" "Ed25519"
PKI_SIG_USEDIGEST to pass the digest value of the data-to-be-signed as the lpData argument.
PKI_ENCODE_BASE64URL PKI_ENCODE_HEXOptions for ECDSA signatures only:
PKI_SIG_DETERMINISTIC PKI_SIG_ASN1DEROptions for RSA-PSS signatures only to set the salt length (default =
hLen):
PKI_PSS_SALTLEN_HLEN PKI_PSS_SALTLEN_MAX PKI_PSS_SALTLEN_20 PKI_PSS_SALTLEN_ZEROand, optionally, add
PKI_MGF_MGF1SHA1 (RSA-PSS only) to force the MGF hash function to be SHA-1 (default = same as signature hash algorithm).Compute a signature value over data in a file.
Public Function sigSignFile ( _ szDataFile As String, _ szKeyFile As String, _ szPassword As String, _ szAlgName As String, _ Optional nOptions As Long = 0 _ ) As String
"" if not required."sha1WithRSAEncryption" "sha224WithRSAEncryption" "sha256WithRSAEncryption" "sha384WithRSAEncryption" "sha512WithRSAEncryption" "md5WithRSAEncryption" "ecdsaWithSHA1" "ecdsaWithSHA224" "ecdsaWithSHA256" "ecdsaWithSHA384" "ecdsaWithSHA512" "RSA-PSS-SHA1" "RSA-PSS-SHA224" "RSA-PSS-SHA256" "RSA-PSS-SHA384" "RSA-PSS-SHA512"
PKI_ENCODE_BASE64URL PKI_ENCODE_HEXOptions for ECDSA signatures only:
PKI_SIG_DETERMINISTIC PKI_SIG_ASN1DEROptions for RSA-PSS signatures only to set the salt length (default =
hLen):
PKI_PSS_SALTLEN_HLEN PKI_PSS_SALTLEN_MAX PKI_PSS_SALTLEN_20 PKI_PSS_SALTLEN_ZEROand, optionally, add
PKI_MGF_MGF1SHA1 (RSA-PSS only) to force the MGF hash function to be SHA-1 (default = same as signature hash algorithm).Verify a signature value over data in a byte array.
Public Function sigVerifyData ( _ szSignature As String, _ lpData() As Byte, _ szCertOrKey As String, _ szAlgName As String, _ Optional nOptions As Long = 0 _ ) As Long
"sha1WithRSAEncryption" "sha224WithRSAEncryption" "sha256WithRSAEncryption" "sha384WithRSAEncryption" "sha512WithRSAEncryption" "md5WithRSAEncryption" "ecdsaWithSHA1" "ecdsaWithSHA224" "ecdsaWithSHA256" "ecdsaWithSHA384" "ecdsaWithSHA512" "RSA-PSS-SHA1" "RSA-PSS-SHA224" "RSA-PSS-SHA256" "RSA-PSS-SHA384" "RSA-PSS-SHA512" "Ed25519"
PKI_SIG_USEDIGEST to pass the digest value of the data-to-be-signed as the lpData argument instead of the data itself.
Add PKI_MGF_MGF1SHA1 (RSA-PSS only) to force the MGF hash function to be SHA-1 (default = same as signature hash algorithm).Query an S/MIME entity for selected information.
Public Function smimeQuery ( _ szFileIn As String, _ szQuery As String, _ Optional nOptions As Long = 0 _ ) As String
"content-type" "smime-type" "encoding" "name" "filename"
Debug.Print smimeQuery("cmsalice2bob-smime-env.txt", "smime-type")
enveloped-dataWipe a byte array securely.
Public Function wipeBytes ( _ ByRef lpToWipe() As Byte _ ) As Byte()
Dim lpData() As Byte
lpData = cnvFromHex("DEADBEEF")
Debug.Print "BEFORE: 0x(" & cnvToHex(lpData) & ")" ' BEFORE: 0x(DEADBEEF)
Call wipeBytes(lpData)
Debug.Print "AFTER: 0x(" & cnvToHex(lpData) & ")" ' AFTER: 0x()Wipe a string securely and return an empty string.
Public Function wipeString ( _ ByRef szToWipe As String _ ) As String
szToWipe = wipeString(szToWipe)Dim strData As String strData = "my deepest secrets" strData = wipeString(strData)
Calculate the thumbprint (message digest value) of an X.509 certificate.
Public Function x509CertThumb ( _ szCertFile As String, _ Optional nOptions As Long = 0 _ ) As String
PKI_HASH_SHA1 (0 = default) PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512 PKI_HASH_MD5
Calculate the message digest hash of the PKCS #7 issuerAndSerialNumber value of an X.509 certificate.
Public Function x509HashIssuerAndSN ( _ szCertFile As String, _ Optional nOptions As Long = 0 _ ) As String
PKI_HASH_SHA1 (0 = default) PKI_HASH_SHA224 PKI_HASH_SHA256 PKI_HASH_SHA384 PKI_HASH_SHA512 PKI_HASH_MD5
Query an X.509 certificate file for selected information.
Public Function x509QueryCert ( _ szCertFile As String, _ szQuery As String, _ Optional nOptions As Long = 0 _ ) As String
"version" "serialNumber" "signatureAlgorithm" "sigAlgId" "signatureValue" "notBefore" "notAfter" "issuerName" "subjectName" "subjectPublicKeyAlgorithm" "subjectKeyIdentifier" "authorityKeyIdentifier" "rfc822Name" "isCA" "keyUsageString" "extKeyUsageString" "cRLDistributionPointsURI" "authorityInfoAccessURI" "subjectAltName" "hashAlgorithm" "pssParams"
PKI_X509_LATIN1 or PKI_X509_UTF8 PKI_X509_LDAP PKI_X509_DECIMAL
PKI_X509_UTF8 will output attribute string encoded in UTF-8.
PKI_X509_LATIN1 will attempt to convert output to Latin-1 encoding.
Debug.Print x509QueryCert("AliceRSASignByCarl.cer", "subjectName")
CN=AliceRSARead an X.509 certificate into a base64-encoded string from PKCS-7 "certs-only" data.
Public Function x509ReadCertStringFromP7Chain ( _ szP7cFile As String, _ nIndex As Long, _ Optional nOptions As Long = 0 _ ) As String
X509_GetCertCountInP7Chain() to find number of certificates in the chain.Read an X.509 certificate into a base64-encoded string from PKCS-12 PFX/.p12 data.
Public Function x509ReadCertStringFromPFX ( _ szPfxFile As String, _ szPassword As String, _ Optional nOptions As Long = 0 _ ) As String
"" if certificate is not encrypted.Read an X.509 certificate into a base64-encoded string.
Public Function x509ReadStringFromFile ( _ szCertFile As String, _ Optional nOptions As Long = 0 _ ) As String
Dump details of an X.509 certificate or a X.509 certificate revocation list (CRL) or a PKCS-10 certificate signing request (CSR) to a string.
Public Function x509TextDumpToString ( _ szCertFile As String, _ Optional nOptions As Long = 0 _ ) As String
PKI_X509_LATIN1 PKI_X509_LDAP PKI_X509_DECIMAL
Generate bytes using an eXtendable-Output Function (XOF).
Public Function xofBytes ( _ nBytes As Long, _ lpMessage() As Byte, _ nOptions As Long _ ) As Byte()
PKI_XOF_SHAKE128 PKI_XOF_SHAKE256 PKI_XOF_MGF1_SHA1 PKI_XOF_MGF1_SHA256 PKI_XOF_MGF1_SHA512
See Using with C++ (STL).
To program in the .NET languages C# and VB.NET (VB20xx), use the classes and methods in the
CryptoSys PKI Pro .NET Class Library diCrSysPKINet.dll.
There is a full listing of all the .NET methods at List of .NET Methods.
For more guidance on programming, see Using with .NET: C# and VB.NET.
The following table shows the cross-reference between the core VB6/C functions and the .NET methods. Plus, where relevant, the equivalent VBA wrapper function.
The .NET classes and methods have different parameters and return values to the VB6/C functions described above.
Full details are provided in Summary of .NET Classes below
and also in the help file CryptoSysPKI.NET.chm available separately.
This manual includes the complete information from the .NET Help File plus cross-references to the equivalent VB6/C functions and examples in VB.NET. For a summary showing the VB6/C equivalent functions for these .NET methods, see Cross-reference between Functions and .NET Methods.
Class index: Asn1 | Cipher | Cms | Cnv | Compr | Ecc | General | Hash | Hmac | Hpke | Kdf | Ocsp | Pbe | Pem | Pfx | Prf | Pwd | Rng | Rsa | Sig | Smime | Tdea | Wipe | X509 | Xof
Class index: Asn1 | Cipher | Cms | Cnv | Compr | Ecc | General | Hash | Hmac | Hpke | Kdf | Ocsp | Pbe | Pem | Pfx | Prf | Pwd | Rng | Rsa | Sig | Smime | Tdea | Wipe | X509 | Xof
Dump details of an ASN.1 formatted data file to a text file.
public static int TextDump( string outputFile, string fileOrPEMString, Asn1.Options options )
Public Shared Function TextDump ( _ outputFile As String, _ fileOrPEMString As String, _ options As Asn1.Options _ ) As Integer
VB6/C equivalent: ASN1_TextDump
Dump details of ASN.1 formatted data to a string.
public static string TextDumpToString( string fileOrPEMString, Asn1.Options options )
Public Shared Function TextDumpToString ( _ fileOrPEMString As String, _ options As Asn1.Options _ ) As String
VB6/C equivalent: ASN1_TextDumpToString
Describe the type of ASN.1 data.
public static string Type( string fileOrPEMString )
Public Shared Function Type ( _ fileOrPEMString As String _ ) As String
VB6/C equivalent: ASN1_Type
Return the block size in bytes for a given cipher algorithm.
public static int BlockBytes( CipherAlgorithm alg )
Public Shared Function BlockBytes ( _ alg As CipherAlgorithm _ ) As Integer
Decrypt data block in byte array.
public static byte[] Decrypt( byte[] input, byte[] key, byte[] iv, CipherAlgorithm cipherAlg, Mode mode )
Public Shared Function Decrypt ( _ input As Byte(), _ key As Byte(), _ iv As Byte(), _ cipherAlg As CipherAlgorithm, _ mode As Mode _ ) As Byte()
VB6/C equivalent: CIPHER_Bytes
Decrypt data in a byte array using the specified block cipher algorithm, mode and padding.
public static byte[] Decrypt( byte[] input, byte[] key, byte[] iv, CipherAlgorithm cipherAlg, Mode mode, Padding pad, Cipher.Opts opts )
Public Shared Function Decrypt ( _ input As Byte(), _ key As Byte(), _ iv As Byte(), _ cipherAlg As CipherAlgorithm, _ mode As Mode, _ pad As Padding, _ opts As Cipher.Opts _ ) As Byte()
VB6/C equivalent: CIPHER_DecryptBytes
Decrypt data block as hex-encoded string.
public static string Decrypt( string inputHex, string keyHex, string ivHex, CipherAlgorithm cipherAlg, Mode mode )
Public Shared Function Decrypt ( _ inputHex As String, _ keyHex As String, _ ivHex As String, _ cipherAlg As CipherAlgorithm, _ mode As Mode _ ) As String
VB6/C equivalent: CIPHER_Hex
Decrypt hex-encoded data using specified block cipher algorithm, mode and padding.
public static string Decrypt( string inputHex, string keyHex, string ivHex, CipherAlgorithm cipherAlg, Mode mode, Padding pad, Cipher.Opts opts )
Public Shared Function Decrypt ( _ inputHex As String, _ keyHex As String, _ ivHex As String, _ cipherAlg As CipherAlgorithm, _ mode As Mode, _ pad As Padding, _ opts As Cipher.Opts _ ) As String
VB6/C equivalent: CIPHER_DecryptHex
Decrypt data using the AES-GCM authenticated encryption algorithm.
public static byte[] DecryptAEAD( byte[] input, byte[] key, byte[] iv, AeadAlgorithm aeadAlg )
Public Shared Function DecryptAEAD ( _ input As Byte(), _ key As Byte(), _ iv As Byte(), _ aeadAlg As AeadAlgorithm _ ) As Byte()
VB6/C equivalent: CIPHER_DecryptAEAD
Decrypt data using the AES-GCM authenticated encryption algorithm with AAD and options.
public static byte[] DecryptAEAD( byte[] input, byte[] key, byte[] iv, byte[] aad, AeadAlgorithm aeadAlg, Cipher.Opts opts )
Public Shared Function DecryptAEAD ( _ input As Byte(), _ key As Byte(), _ iv As Byte(), _ aad As Byte(), _ aeadAlg As AeadAlgorithm, _ opts As Cipher.Opts _ ) As Byte()
VB6/C equivalent: CIPHER_DecryptAEAD
Encrypt data block in byte array.
public static byte[] Encrypt( byte[] input, byte[] key, byte[] iv, CipherAlgorithm cipherAlg, Mode mode )
Public Shared Function Encrypt ( _ input As Byte(), _ key As Byte(), _ iv As Byte(), _ cipherAlg As CipherAlgorithm, _ mode As Mode _ ) As Byte()
VB6/C equivalent: CIPHER_Bytes
Encrypt data in a byte array using the specified block cipher algorithm, mode and padding.
public static byte[] Encrypt( byte[] input, byte[] key, byte[] iv, CipherAlgorithm cipherAlg, Mode mode, Padding pad, Cipher.Opts opts )
Public Shared Function Encrypt ( _ input As Byte(), _ key As Byte(), _ iv As Byte(), _ cipherAlg As CipherAlgorithm, _ mode As Mode, _ pad As Padding, _ opts As Cipher.Opts _ ) As Byte()
VB6/C equivalent: CIPHER_EncryptBytes
Encrypt data block as hex-encoded string.
public static string Encrypt( string inputHex, string keyHex, string ivHex, CipherAlgorithm cipherAlg, Mode mode )
Public Shared Function Encrypt ( _ inputHex As String, _ keyHex As String, _ ivHex As String, _ cipherAlg As CipherAlgorithm, _ mode As Mode _ ) As String
VB6/C equivalent: CIPHER_Hex
Encrypt hex-encoded data using specified block cipher algorithm, mode and padding.
public static string Encrypt( string inputHex, string keyHex, string ivHex, CipherAlgorithm cipherAlg, Mode mode, Padding pad, Cipher.Opts opts )
Public Shared Function Encrypt ( _ inputHex As String, _ keyHex As String, _ ivHex As String, _ cipherAlg As CipherAlgorithm, _ mode As Mode, _ pad As Padding, _ opts As Cipher.Opts _ ) As String
VB6/C equivalent: CIPHER_EncryptHex
Encrypt data using the AES-GCM authenticated encryption algorithm.
public static byte[] EncryptAEAD( byte[] input, byte[] key, byte[] iv, AeadAlgorithm aeadAlg )
Public Shared Function EncryptAEAD ( _ input As Byte(), _ key As Byte(), _ iv As Byte(), _ aeadAlg As AeadAlgorithm _ ) As Byte()
VB6/C equivalent: CIPHER_EncryptAEAD
Encrypt data using the AES-GCM authenticated encryption algorithm with AAD and options.
public static byte[] EncryptAEAD( byte[] input, byte[] key, byte[] iv, byte[] aad, AeadAlgorithm aeadAlg, Cipher.Opts opts )
Public Shared Function EncryptAEAD ( _ input As Byte(), _ key As Byte(), _ iv As Byte(), _ aad As Byte(), _ aeadAlg As AeadAlgorithm, _ opts As Cipher.Opts _ ) As Byte()
VB6/C equivalent: CIPHER_EncryptAEAD
Decrypt a file.
public static int FileDecrypt( string fileOut, string fileIn, byte[] key, byte[] iv, CipherAlgorithm cipherAlg, Mode mode, Padding pad, Cipher.Opts opts )
Public Shared Function FileDecrypt ( _ fileOut As String, _ fileIn As String, _ key As Byte(), _ iv As Byte(), _ cipherAlg As CipherAlgorithm, _ mode As Mode, _ pad As Padding, _ opts As Cipher.Opts _ ) As Integer
VB6/C equivalent: CIPHER_FileDecrypt
Decrypt a file passing key and IV as hex strings.
public static int FileDecrypt( string fileOut, string fileIn, string keyHex, string ivHex, CipherAlgorithm cipherAlg, Mode mode, Padding pad, Cipher.Opts opts )
Public Shared Function FileDecrypt ( _ fileOut As String, _ fileIn As String, _ keyHex As String, _ ivHex As String, _ cipherAlg As CipherAlgorithm, _ mode As Mode, _ pad As Padding, _ opts As Cipher.Opts _ ) As Integer
VB6/C equivalent: CIPHER_FileDecrypt
Encrypt a file.
public static int FileEncrypt( string fileOut, string fileIn, byte[] key, byte[] iv, CipherAlgorithm cipherAlg, Mode mode, Padding pad, Cipher.Opts opts )
Public Shared Function FileEncrypt ( _ fileOut As String, _ fileIn As String, _ key As Byte(), _ iv As Byte(), _ cipherAlg As CipherAlgorithm, _ mode As Mode, _ pad As Padding, _ opts As Cipher.Opts _ ) As Integer
VB6/C equivalent: CIPHER_FileEncrypt
Encrypt a file passing key and IV as hex strings.
public static int FileEncrypt( string fileOut, string fileIn, string keyHex, string ivHex, CipherAlgorithm cipherAlg, Mode mode, Padding pad, Cipher.Opts opts )
Public Shared Function FileEncrypt ( _ fileOut As String, _ fileIn As String, _ keyHex As String, _ ivHex As String, _ cipherAlg As CipherAlgorithm, _ mode As Mode, _ pad As Padding, _ opts As Cipher.Opts _ ) As Integer
VB6/C equivalent: CIPHER_FileEncrypt
Return the key size in bytes for a given cipher algorithm.
public static int KeyBytes( CipherAlgorithm alg )
Public Shared Function KeyBytes ( _ alg As CipherAlgorithm _ ) As Integer
Unwrap (decrypt) key material with a key-encryption key.
public static byte[] KeyUnwrap( byte[] data, byte[] kek, CipherAlgorithm cipherAlg )
Public Shared Function KeyUnwrap ( _ data As Byte(), _ kek As Byte(), _ cipherAlg As CipherAlgorithm _ ) As Byte()
VB6/C equivalent: CIPHER_KeyUnwrap
Wrap (encrypt) key material with a key-encryption key.
public static byte[] KeyWrap( byte[] data, byte[] kek, CipherAlgorithm cipherAlg )
Public Shared Function KeyWrap ( _ data As Byte(), _ kek As Byte(), _ cipherAlg As CipherAlgorithm _ ) As Byte()
VB6/C equivalent: CIPHER_KeyWrap
Pad byte array to correct length for ECB and CBC encryption.
public static byte[] Pad( byte[] input, CipherAlgorithm cipherAlg, Padding pad )
Public Shared Function Pad ( _ input As Byte(), _ cipherAlg As CipherAlgorithm, _ pad As Padding _ ) As Byte()
VB6/C equivalent: PAD_BytesBlock
Pad hex-encoded string to correct length for ECB and CBC encryption.
public static string Pad( string inputHex, CipherAlgorithm cipherAlg, Padding pad )
Public Shared Function Pad ( _ inputHex As String, _ cipherAlg As CipherAlgorithm, _ pad As Padding _ ) As String
VB6/C equivalent: PAD_HexBlock
Remove padding from an encryption block.
public static byte[] Unpad( byte[] input, CipherAlgorithm cipherAlg, Padding pad )
Public Shared Function Unpad ( _ input As Byte(), _ cipherAlg As CipherAlgorithm, _ pad As Padding _ ) As Byte()
VB6/C equivalent: PAD_UnpadBytes
Remove padding from a hex-encoded encryption block.
public static string Unpad( string inputHex, CipherAlgorithm cipherAlg, Padding pad )
Public Shared Function Unpad ( _ inputHex As String, _ cipherAlg As CipherAlgorithm, _ pad As Padding _ ) As String
VB6/C equivalent: PAD_UnpadHex
Extract the message digest from a signed-data CMS object file and verify the signature.
public static string GetSigDataDigest( string inputFile, string certFile )
Public Shared Function GetSigDataDigest ( _ inputFile As String, _ certFile As String _ ) As String
VB6/C equivalent: CMS_GetSigDataDigest
Find ID of message digest hash algorithm used to make signature.
public static int GetSigHashAlgorithm( string inputFile, string certFile )
Public Shared Function GetSigHashAlgorithm ( _ inputFile As String, _ certFile As String _ ) As Integer
Create a new CMS compressed-data file (.p7z) from an existing input file.
public static int MakeComprData( string outputFile, string inputFile )
Public Shared Function MakeComprData ( _ outputFile As String, _ inputFile As String _ ) As Integer
VB6/C equivalent: CMS_MakeComprData
Create a "detached signature" CMS signed-data object file from a message digest of the content (advanced algorithms).
public static int MakeDetachedSig( string outputFile, string hexDigest, string certList, string privateKey, HashAlgorithm hashAlg, Cms.SigDataOptions advOptions )
Public Shared Function MakeDetachedSig ( _ outputFile As String, _ hexDigest As String, _ certList As String, _ privateKey As String, _ hashAlg As HashAlgorithm, _ advOptions As Cms.SigDataOptions _ ) As Integer
VB6/C equivalent: CMS_MakeDetachedSig
Create a CMS enveloped-data object (default recipient parameters).
public static int MakeEnvData( string outputFile, string inputFile, string certList, CipherAlgorithm cipherAlg, Cms.EnvDataOptions advOptions )
Public Shared Function MakeEnvData ( _ outputFile As String, _ inputFile As String, _ certList As String, _ cipherAlg As CipherAlgorithm, _ advOptions As Cms.EnvDataOptions _ ) As Integer
VB6/C equivalent: CMS_MakeEnvData
Create a CMS enveloped-data object (advanced options).
public static int MakeEnvData( string outputFile, string inputFile, string certList, CipherAlgorithm cipherAlg, Cms.KeyEncrAlgorithm keyEncrAlg, HashAlgorithm hashAlg, Cms.EnvDataOptions advOptions, Kdf.KdfAlg kdfAlg, Kdf.KeyWrapAlg keyWrapAlg, string keyString, int count, Cms.ContentEncrAlg contEncrAlg )
Public Shared Function MakeEnvData ( _ outputFile As String, _ inputFile As String, _ certList As String, _ cipherAlg As CipherAlgorithm, _ keyEncrAlg As Cms.KeyEncrAlgorithm, _ hashAlg As HashAlgorithm, _ advOptions As Cms.EnvDataOptions, _ kdfAlg As Kdf.KdfAlg, _ keyWrapAlg As Kdf.KeyWrapAlg, _ keyString As String, _ count As Integer, _ contEncrAlg As Cms.ContentEncrAlg _ ) As Integer
Special cases: Set as "type=@pwri" to create a single recipientInfo of the PasswordRecipientInfo (pwri) type; or set as "type=@kekri,keyid=<string>" to create a single recipientInfo of the KEKRecipientInfo (kekri) type. See Remarks.
If certList is set to "type=@pwri" then a single recipientInfo will be created of PasswordRecipientInfo type (pwri). The password must be passed in the keyString parameter. The parameters keyEncrAlg, kdfAlg and keyWrapAlg are ignored in this case. If certList is set to "type=@kekri,keyid=<string>" then a single recipientInfo will be created of KEKRecipientInfo type (kekri). The key encryption key (KEK) must be passed in the keyString parameter. The parameters keyEncrAlg, hashAlg and kdfAlg are ignored in this case.
// Create an enveloped CMS object (ktri type) to Bob using Bob's RSA key n = Cms.MakeEnvData("cms2bob_aes128.p7m", "excontent.txt", "BobRSASignByCarl.cer", CipherAlgorithm.Aes128, Cms.KeyEncrAlgorithm.Rsa_Oaep); // Create an enveloped CMS object (kekri type) using a previously distributed symmetric key-encryption key (KEK) n = Cms.MakeEnvData("cms_envdata_kekri.p7m", "excontent.txt", "type=@kekri,keyid=ourcommonkey", CipherAlgorithm.Aes256, hashAlg: HashAlgorithm.Sha256, keyWrapAlg:Kdf.KeyWrapAlg.Aes128_wrap, keyString: "#x0123456789ABCDEFF0E1D2C3B4A59687");
VB6/C equivalent: CMS_MakeEnvData
Create a CMS enveloped-data object from data in a byte array.
public static int MakeEnvDataFromBytes( string outputFile, byte[] inputData, string certList, CipherAlgorithm cipherAlg, Cms.KeyEncrAlgorithm keyEncrAlg, HashAlgorithm hashAlg, Cms.EnvDataOptions advOptions, Kdf.KdfAlg kdfAlg, Kdf.KeyWrapAlg keyWrapAlg, string keyString, int count, Cms.ContentEncrAlg contEncrAlg )
Public Shared Function MakeEnvDataFromBytes ( _ outputFile As String, _ inputData As Byte(), _ certList As String, _ cipherAlg As CipherAlgorithm, _ keyEncrAlg As Cms.KeyEncrAlgorithm, _ hashAlg As HashAlgorithm, _ advOptions As Cms.EnvDataOptions, _ kdfAlg As Kdf.KdfAlg, _ keyWrapAlg As Kdf.KeyWrapAlg, _ keyString As String, _ count As Integer, _ contEncrAlg As Cms.ContentEncrAlg _ ) As Integer
Special cases: Set as "type=@pwri" to create a single recipientInfo of the PasswordRecipientInfo (pwri) type; or set as "type=@kekri,keyid=<string>" to create a single recipientInfo of the KEKRecipientInfo (kekri) type. See Remarks.
VB6/C equivalent: CMS_MakeEnvDataFromBytes
Create a CMS enveloped-data object from an ASCII string (default recipient parameters).
public static int MakeEnvDataFromString( string outputFile, string inputData, string certList, CipherAlgorithm cipherAlg, Cms.EnvDataOptions advOptions )
Public Shared Function MakeEnvDataFromString ( _ outputFile As String, _ inputData As String, _ certList As String, _ cipherAlg As CipherAlgorithm, _ advOptions As Cms.EnvDataOptions _ ) As Integer
VB6/C equivalent: CMS_MakeEnvDataFromString
Create a CMS enveloped-data object from an ASCII string (advanced options).
public static int MakeEnvDataFromString( string outputFile, string inputData, string certList, CipherAlgorithm cipherAlg, Cms.KeyEncrAlgorithm keyEncrAlg, HashAlgorithm hashAlg, Cms.EnvDataOptions advOptions, Kdf.KdfAlg kdfAlg, Kdf.KeyWrapAlg keyWrapAlg, string keyString, int count, Cms.ContentEncrAlg contEncrAlg )
Public Shared Function MakeEnvDataFromString ( _ outputFile As String, _ inputData As String, _ certList As String, _ cipherAlg As CipherAlgorithm, _ keyEncrAlg As Cms.KeyEncrAlgorithm, _ hashAlg As HashAlgorithm, _ advOptions As Cms.EnvDataOptions, _ kdfAlg As Kdf.KdfAlg, _ keyWrapAlg As Kdf.KeyWrapAlg, _ keyString As String, _ count As Integer, _ contEncrAlg As Cms.ContentEncrAlg _ ) As Integer
Special cases: Set as "type=@pwri" to create a single recipientInfo of the PasswordRecipientInfo type (pwri); or set as "type=@kekri,keyid=<string>" to create a single recipientInfo of the KEKRecipientInfo type (kekri). See Remarks.
VB6/C equivalent: CMS_MakeEnvDataFromString
Create a CMS object of type SignedData from an input data file (advanced options including RSA-PSS).
public static int MakeSigData( string outputFile, string inputFile, string certList, string privateKey, Cms.SigAlg sigAlg, Cms.SigDataOptions advOptions )
Public Shared Function MakeSigData ( _ outputFile As String, _ inputFile As String, _ certList As String, _ privateKey As String, _ sigAlg As Cms.SigAlg, _ advOptions As Cms.SigDataOptions _ ) As Integer
StringBuilder sbPrivateKey = Rsa.ReadPrivateKey("AlicePrivRSASign.p8e", "password"); string fnameOutput = "BasicSignByAlice.bin"; string fnameInput = "excontent.txt"; string fnameCert = "AliceRSASignByCarl.cer"; int n = Cms.MakeSigData(fnameOutput, fnameInput, fnameCert, sbPrivateKey.ToString(), Cms.SigAlg.Default, 0);
VB6/C equivalent: CMS_MakeSigData
Create a CMS object of type SignedData from an input data file using RSASSA-PKCS1V1_5 with options.
public static int MakeSigData( string outputFile, string inputFile, string certList, string privateKey, HashAlgorithm hashAlg, Cms.SigDataOptions advOptions )
Public Shared Function MakeSigData ( _ outputFile As String, _ inputFile As String, _ certList As String, _ privateKey As String, _ hashAlg As HashAlgorithm, _ advOptions As Cms.SigDataOptions _ ) As Integer
VB6/C equivalent: CMS_MakeSigData
Create a CMS object of type SignedData from an array of bytes.
public static int MakeSigDataFromBytes( string outputFile, byte[] inputData, string certList, string privateKey, Cms.SigAlg sigAlg, Cms.SigDataOptions advOptions )
Public Shared Function MakeSigDataFromBytes ( _ outputFile As String, _ inputData As Byte(), _ certList As String, _ privateKey As String, _ sigAlg As Cms.SigAlg, _ advOptions As Cms.SigDataOptions _ ) As Integer
VB6/C equivalent: CMS_MakeSigDataFromBytes
Create a SignedData object from a "pseudo" object.
public static int MakeSigDataFromPseudo( string outputFile, string inputPseudoFile, byte[] sigValue, Cms.Format format )
Public Shared Function MakeSigDataFromPseudo ( _ outputFile As String, _ inputPseudoFile As String, _ sigValue As Byte(), _ format As Cms.Format _ ) As Integer
VB6/C equivalent: CMS_MakeSigDataFromSigValue
Create a CMS object of type SignedData using a pre-computed signature (advanced algorithms).
public static int MakeSigDataFromSigValue( string outputFile, byte[] sigValue, byte[] contentData, string certList, HashAlgorithm hashAlg, Cms.SigDataOptions advOptions )
Public Shared Function MakeSigDataFromSigValue ( _ outputFile As String, _ sigValue As Byte(), _ contentData As Byte(), _ certList As String, _ hashAlg As HashAlgorithm, _ advOptions As Cms.SigDataOptions _ ) As Integer
VB6/C equivalent: CMS_MakeSigDataFromSigValue
Create a CMS object of type SignedData from an input string (advanced options including RSA-PSS).
public static int MakeSigDataFromString( string outputFile, string inputData, string certList, string privateKey, Cms.SigAlg sigAlg, Cms.SigDataOptions advOptions )
Public Shared Function MakeSigDataFromString ( _ outputFile As String, _ inputData As String, _ certList As String, _ privateKey As String, _ sigAlg As Cms.SigAlg, _ advOptions As Cms.SigDataOptions _ ) As Integer
VB6/C equivalent: CMS_MakeSigDataFromString
Create a CMS object of type SignedData from an input string using RSASSA-PKCS1V1_5 with options.
public static int MakeSigDataFromString( string outputFile, string inputData, string certList, string privateKey, HashAlgorithm hashAlg, Cms.SigDataOptions advOptions )
Public Shared Function MakeSigDataFromString ( _ outputFile As String, _ inputData As String, _ certList As String, _ privateKey As String, _ hashAlg As HashAlgorithm, _ advOptions As Cms.SigDataOptions _ ) As Integer
VB6/C equivalent: CMS_MakeSigDataFromString
Query a CMS enveloped-data object file for selected information.
public static string QueryEnvData( string inputFile, string query )
Public Shared Function QueryEnvData ( _ inputFile As String, _ query As String _ ) As String
Valid queries are:
| "version" | envelopedData CMSVersion (edVer) value, e.g. "0". |
| "recipientInfoVersion" | recipientInfo version (riVer) value. |
| "recipientInfoType" | Type of recipientInfo, e.g. ktri, kari, ... |
| "CountOfRecipientInfos" | Number of RecipientInfos included in the data. |
| "recipientIssuerName" | Distinguished Name of recipient's certificate issuer. |
| "recipientSerialNumber" | serialNumber of recipient's certificate in hex format |
| "keyEncryptionAlgorithm" | keyEncryptionAlgorithm, e.g. "rsaEncryption". |
| "keyEncryptionFlags" | Bit flags used for the key encryption algorithm (ktri only). |
| "SizeOfEncryptedKey" | Size (in bytes) of the EncryptedKey. |
| "encryptedKey" | EncryptedKey value encoded in hex. |
| "oaepParams" | Parameters used for RSA-OAEP (if applicable). |
| "keyWrapAlgorithm" | Key wrap algorithm, e.g. "aes128-wrap" (kari and kekri only). |
| "originatorKeyAlgorithm" | OriginatorPublicKey algorithm, e.g. "ecPublicKey" (kari only). |
| "originatorPublicKey" | OriginatorPublicKey publicKey value encoded in hex (kari only). |
| "keyid" | keyIdentifier for KEKRecipientInfo (kekri) type. |
| "contentEncryptionAlgorithm" | contentEncryptionAlgorithm, e.g. "des-EDE3-CBC". |
| "SizeOfEncryptedContent" | Size (in bytes) of the EncryptedContent. |
| "encryptedContent" | EncryptedContent encoded in hex. |
| "iv" | Initialization vector encoded in hex. |
VB6/C equivalent: CMS_QueryEnvData
Query a CMS signed-data object for selected information.
public static string QuerySigData( string inputFile, string query )
Public Shared Function QuerySigData ( _ inputFile As String, _ query As String _ ) As String
Valid queries are:
| "version" | signedData version (sdVer) value, e.g. "1". |
| "eContentType" | ContentType of the EncapsulatedContentInfo, e.g. "data". |
| "HASeContent" | "1" if eContent is present; "0" if not. |
| "CountOfCertificates" | Number of certificates included in the data. |
| "CountOfSignerInfos" | Number of SignerInfos included in the data. |
| "signerInfoVersion" | signerInfo version (siVer) value. |
| "digestAlgorithm" | digestAlgorithm, e.g. "sha1". |
| "signatureAlgorithm" | signatureAlgorithm, e.g. "rsaEncryption". |
| "signatureValue" | Signature value encoded in hex. |
| "HASsignedAttributes" | "1" if signedAttributes (authenticatedAttributes) are present; "0" if not. |
| "DigestOfSignedAttrs" | Computed digest over signed attributes, if present, using digestAlgorithm. |
| "DigestOfeContent" | Computed digest over eContent, if present, using digestAlgorithm. |
| "signingTime" | signingTime attribute in format "2005-12-31 23:30:59" |
| "messageDigest" | messageDigest attribute in hexadecimal format, if present |
| "pssParams" | Parameters used for RSA-PSS (if applicable). |
| "HASsigningCertificate" | "1" if an ESS signingCertificate is present; "0" if not. |
| "signingCertHash" | certHash value of ESS signing certificate, if present, encoded in hex. |
| "HASalgorithmProtection" | "1" if a cmsAlgorithmProtection attribute is present; "0" if not. |
VB6/C equivalent: CMS_QuerySigData
Read and extract the decompressed contents of a CMS compressed-data file.
public static int ReadComprData( string outputFile, string inputFile, Cms.ComprDataOptions opts )
Public Shared Function ReadComprData ( _ outputFile As String, _ inputFile As String, _ opts As Cms.ComprDataOptions _ ) As Integer
VB6/C equivalent: CMS_ReadComprData
Read and decrypt a CMS enveloped-data object to a byte array.
public static byte[] ReadEnvDataToBytes( string inputFile, string x509File, string privateKey )
Public Shared Function ReadEnvDataToBytes ( _ inputFile As String, _ x509File As String, _ privateKey As String _ ) As Byte()
// Read in content to a byte array byte[] b = Cms.ReadEnvDataToBytes(inputFile, "", privateKey); // Convert to a .NET string (assuming UTF-8 encoded) string s = System.Text.Encoding.UTF8.GetString(b);
VB6/C equivalent: CMS_ReadEnvDataToBytes
Read and decrypt a CMS enveloped-data object to a file.
public static int ReadEnvDataToFile( string outputFile, string inputFile, string x509File, string privateKey, Cms.ReadOptions opts )
Public Shared Function ReadEnvDataToFile ( _ outputFile As String, _ inputFile As String, _ x509File As String, _ privateKey As String, _ opts As Cms.ReadOptions _ ) As Integer
VB6/C equivalent: CMS_ReadEnvData
Read and decrypt a CMS enveloped-data object to a string.
public static string ReadEnvDataToString( string inputFile, string x509File, string privateKey )
Public Shared Function ReadEnvDataToString ( _ inputFile As String, _ x509File As String, _ privateKey As String _ ) As String
VB6/C equivalent: CMS_ReadEnvDataToString
Read the content from a CMS signed-data object directly into a byte array.
public static byte[] ReadSigDataToBytes( string inputFile )
Public Shared Function ReadSigDataToBytes ( _ inputFile As String _ ) As Byte()
// Read in content to a byte array byte[] b = Cms.ReadSigDataToBytes(inputFile); // Convert to a .NET string (assumed UTF-8 encoded) string s = System.Text.Encoding.UTF8.GetString(b);
VB6/C equivalent: CMS_ReadSigDataToBytes
Read the content from a CMS signed-data object file.
public static int ReadSigDataToFile( string outputFile, string inputFile, Cms.ReadOptions opts )
Public Shared Function ReadSigDataToFile ( _ outputFile As String, _ inputFile As String, _ opts As Cms.ReadOptions _ ) As Integer
VB6/C equivalent: CMS_ReadSigData
Read the content from a CMS signed-data object directly into a string.
public static string ReadSigDataToString( string inputFile )
Public Shared Function ReadSigDataToString ( _ inputFile As String _ ) As String
VB6/C equivalent: CMS_ReadSigDataToString
Verify the signature and content of a signed-data CMS object file.
public static int VerifySigData( string inputFile, string certFile, string hexDigest, Cms.SigDataOptions advOptions )
Public Shared Function VerifySigData ( _ inputFile As String, _ certFile As String, _ hexDigest As String, _ advOptions As Cms.SigDataOptions _ ) As Integer
VB6/C equivalent: CMS_VerifySigData
Filter non-base64 characters from a string.
public static string Base64Filter( string s )
Public Shared Function Base64Filter ( _ s As String _ ) As String
VB6/C equivalent: CNV_B64Filter
Convert hexadecimal-encoded data into base64-encoded data.
public static string Base64FromHex( string s )
Public Shared Function Base64FromHex ( _ s As String _ ) As String
Convert encoding of byte array between UTF-8 and Latin-1.
public static byte[] ByteEncoding( byte[] data, Cnv.EncodingConversion direction )
Public Shared Function ByteEncoding ( _ data As Byte(), _ direction As Cnv.EncodingConversion _ ) As Byte()
VB6/C equivalent: CNV_ByteEncoding
Check that a byte array contains only valid UTF-8 encoded characters.
public static int CheckUTF8( byte[] b )
Public Shared Function CheckUTF8 ( _ b As Byte() _ ) As Integer
Zero if the encoded bytes is invalid UTF-8, or a positive number if the input contains valid UTF-8 data, where the value of the number indicates the nature of the encoded characters:
| 0 | Not valid UTF-8 |
| 1 | Valid UTF-8, all chars are 7-bit ASCII |
| 2 | Valid UTF-8, contains at least one multi-byte character equivalent to 8-bit ANSI |
| 3 | Valid UTF-8, contains at least one multi-byte character that cannot be represented in a single-byte character set |
VB6/C equivalent: CNV_CheckUTF8Bytes
Check that a file contains only valid UTF-8 encoded characters.
public static int CheckUTF8File( string fileName )
Public Shared Function CheckUTF8File ( _ fileName As String _ ) As Integer
Zero if the encoded bytes is invalid UTF-8, or a positive number if the input contains valid UTF-8 data, where the value of the number indicates the nature of the encoded characters:
| 0 | Not valid UTF-8 |
| 1 | Valid UTF-8, all chars are 7-bit ASCII |
| 2 | Valid UTF-8, contains at least one multi-byte character equivalent to 8-bit ANSI |
| 3 | Valid UTF-8, contains at least one multi-byte character that cannot be represented in a single-byte character set |
VB6/C equivalent: CNV_CheckUTF8File
Convert a base58-encoded string to an equivalent array of 8-bit unsigned integers.
public static byte[] FromBase58( string s )
Public Shared Function FromBase58 ( _ s As String _ ) As Byte()
VB6/C equivalent: CNV_Base58ToBytes
Convert a base64-encoded string to an equivalent array of 8-bit unsigned integers.
public static byte[] FromBase64( string s )
Public Shared Function FromBase64 ( _ s As String _ ) As Byte()
VB6/C equivalent: CNV_BytesFromB64Str
Convert the specified string representation of a value consisting of hexadecimal (base 16) digits to an equivalent array of 8-bit unsigned integers.
public static byte[] FromHex( string s )
Public Shared Function FromHex ( _ s As String _ ) As Byte()
VB6/C equivalent: CNV_BytesFromHexStr
Filter non-hexadecimal characters from a string.
public static string HexFilter( string s )
Public Shared Function HexFilter ( _ s As String _ ) As String
VB6/C equivalent: CNV_HexFilter
Convert base64-encoded data into hexadecimal-encoded data.
public static string HexFromBase64( string s )
Public Shared Function HexFromBase64 ( _ s As String _ ) As String
Convert the leftmost four bytes of an array to an unsigned 32-bit integer.
public static uint NumFromBytes( byte[] b, Cnv.EndianNess endn )
Public Shared Function NumFromBytes ( _ b As Byte(), _ endn As Cnv.EndianNess _ ) As UInteger
byte[] b = new byte[4] { 0xde, 0xad, 0xbe, 0xef }; uint nb = Cnv.NumFromBytes(b, Cnv.EndianNess.BigEndian); Console.WriteLine("0x" + nb.ToString("x8")); // 0xdeadbeef uint nl = Cnv.NumFromBytes(b, Cnv.EndianNess.LittleEndian); Console.WriteLine("0x" + nl.ToString("x8")); // 0xefbeadde
VB6/C equivalent: CNV_NumFromBytes
Convert a 32-bit integer to an array of 4 bytes.
public static byte[] NumToBytes( uint n, Cnv.EndianNess endn )
Public Shared Function NumToBytes ( _ n As UInteger, _ endn As Cnv.EndianNess _ ) As Byte()
byte[] bb = Cnv.NumToBytes(0xdeadbeef, Cnv.EndianNess.BigEndian); Console.WriteLine(Cnv.ToHex(bb)); // DEADBEEF byte[] bl = Cnv.NumToBytes(0xdeadbeef, Cnv.EndianNess.LittleEndian); Console.WriteLine(Cnv.ToHex(bl)); // EFBEADDE
VB6/C equivalent: CNV_NumToBytes
Reverse the order of a byte array.
public static byte[] ReverseBytes( byte[] data )
Public Shared Function ReverseBytes ( _ data As Byte() _ ) As Byte()
VB6/C equivalent: CNV_ReverseBytes
Retrieve the Windows short path form of the specified path.
public static string ShortPathName( string pathName )
Public Shared Function ShortPathName ( _ pathName As String _ ) As String
VB6/C equivalent: CNV_ShortPathName
Convert a base64-encoded string into a text string.
public static string StringFromBase64( string s )
Public Shared Function StringFromBase64 ( _ s As String _ ) As String
Convert a hexadecimal-encoded string into a text string.
public static string StringFromHex( string s )
Public Shared Function StringFromHex ( _ s As String _ ) As String
Convert 8-bit binary data to equivalent base58-encoded string format.
public static string ToBase58( byte[] binaryData )
Public Shared Function ToBase58 ( _ binaryData As Byte() _ ) As String
VB6/C equivalent: CNV_Base58FromBytes
Convert 8-bit binary data to equivalent base64-encoded string format.
public static string ToBase64( byte[] binaryData )
Public Shared Function ToBase64 ( _ binaryData As Byte() _ ) As String
VB6/C equivalent: CNV_B64StrFromBytes
Convert a string of ANSI characters to equivalent base64-encoded string format.
public static string ToBase64( string s )
Public Shared Function ToBase64 ( _ s As String _ ) As String
VB6/C equivalent: CNV_B64StrFromBytes
Convert 8-bit binary data to equivalent hexadecimal string format.
public static string ToHex( byte[] binaryData )
Public Shared Function ToHex ( _ binaryData As Byte() _ ) As String
VB6/C equivalent: CNV_HexStrFromBytes
Converts a string of ANSI characters to equivalent hexadecimal string format
public static string ToHex( string s )
Public Shared Function ToHex ( _ s As String _ ) As String
Compress data using zlib compression.
public static byte[] Compress( byte[] data )
Public Shared Function Compress ( _ data As Byte() _ ) As Byte()
VB6/C equivalent: COMPR_Compress
Uncompress data using zlib compression.
public static byte[] Uncompress( byte[] data )
Public Shared Function Uncompress ( _ data As Byte() _ ) As Byte()
VB6/C equivalent: COMPR_Uncompress
Compute EC Diffie-Hellman (ECDH) shared secret.
public static byte[] DHSharedSecret( string ourIntPrivateKey, string theirIntPublicKey )
Public Shared Function DHSharedSecret ( _ ourIntPrivateKey As String, _ theirIntPublicKey As String _ ) As Byte()
VB6/C equivalent: ECC_DHSharedSecret
Compute the hash code of an "internal" ECC public or private key string.
public static int KeyHashCode( string intKeyString )
Public Shared Function KeyHashCode ( _ intKeyString As String _ ) As Integer
VB6/C equivalent: ECC_KeyHashCode
Generate an EC public/private key pair and save as two key files.
public static int MakeKeys( string publicKeyfile, string privateKeyFile, Ecc.CurveName curveName, string password, Ecc.PbeScheme pbes, string paramString, Ecc.Format fileFormat )
Public Shared Function MakeKeys ( _ publicKeyfile As String, _ privateKeyFile As String, _ curveName As Ecc.CurveName, _ password As String, _ pbes As Ecc.PbeScheme, _ paramString As String, _ fileFormat As Ecc.Format _ ) As Integer
Valid name-value pairs for paramString are:
| count=integer | To set the iteration count used in the PBKDF2 method, e.g. "count=5000;" [default=2048]. |
| prf=hmac-name | To change the HMAC algorithm used in the PBKDF2 method, e.g. "prf=hmacwithSHA256;" [default=hmacwithSHA1]. |
| rngseed=string | To add some user-supplied entropy for the key generation process, e.g. "rngseed=pqrrr1234xyz;". |
// All default settings... n = Ecc.MakeKeys(pubkeyfile, prikeyfile, Ecc.CurveName.Prime192v1, "password"); // With specialist options... n = Ecc.MakeKeys(pubkeyfile, prikeyfile, Ecc.CurveName.Prime192v1, "password", Ecc.PbeScheme.Pbe_Pbkdf2_aes128_CBC, "count=3999;prf=hmacWithSha256", Ecc.Format.PEM);
VB6/C equivalent: ECC_MakeKeys
Convert an internal EC private key string into an internal EC public key string.
public static string PublicKeyFromPrivate( string internalKey )
Public Shared Function PublicKeyFromPrivate ( _ internalKey As String _ ) As String
VB6/C equivalent: ECC_PublicKeyFromPrivate
Query an EC key string for selected information.
public static string QueryKey( string internalKey, string query )
Public Shared Function QueryKey ( _ internalKey As String, _ query As String _ ) As String
Valid queries are:
| "curveName" | Name of the curve. |
| "keyBits" | Number of bits in the key. |
| "isPrivate" | "1" if key is a private key; "0" if not. |
| "privateKey" | Value of the private key in hex format. |
| "publicKey" | Value of the public key in hex format. |
VB6/C equivalent: ECC_QueryKey
Read an EC key from its hexadecimal representation with options for safe curves.
public static string ReadKeyByCurve( string hexKey, Ecc.CurveName curveName, Ecc.KeyType keyType )
Public Shared Function ReadKeyByCurve ( _ hexKey As String, _ curveName As Ecc.CurveName, _ keyType As Ecc.KeyType _ ) As String
VB6/C equivalent: ECC_ReadKeyByCurve
Read from a file or string containing an EC private key into an "internal" private key string.
public static StringBuilder ReadPrivateKey( string keyFileOrString, string password )
Public Shared Function ReadPrivateKey ( _ keyFileOrString As String, _ password As String _ ) As StringBuilder
VB6/C equivalent: ECC_ReadPrivateKey
Read from a file or string containing an EC public key into an "internal" public key string.
public static StringBuilder ReadPublicKey( string keyFileOrString )
Public Shared Function ReadPublicKey ( _ keyFileOrString As String _ ) As StringBuilder
VB6/C equivalent: ECC_ReadPublicKey
Save an internal EC private key string to an encrypted private key file.
public static int SaveEncKey( string outputFile, string internalKey, string password, Ecc.PbeScheme pbes, string paramString, Ecc.Format fileFormat )
Public Shared Function SaveEncKey ( _ outputFile As String, _ internalKey As String, _ password As String, _ pbes As Ecc.PbeScheme, _ paramString As String, _ fileFormat As Ecc.Format _ ) As Integer
Valid name-value pairs for paramString are:
| count=integer | To set the iteration count used in the PBKDF2 method, e.g. "count=5000;" [default=2048]. |
| prf=hmac-name | To change the HMAC algorithm used in the PBKDF2 method, e.g. "prf=hmacwithSHA256;" [default=hmacwithSHA1]. |
VB6/C equivalent: ECC_SaveEncKey
Save an internal EC key string (public or private) to an unencrypted key file.
public static int SaveKey( string outputFile, string internalKey, Ecc.KeyType keyType, Ecc.Format fileFormat )
Public Shared Function SaveKey ( _ outputFile As String, _ internalKey As String, _ keyType As Ecc.KeyType, _ fileFormat As Ecc.Format _ ) As Integer
VB6/C equivalent: ECC_SaveKey
Return date and time the core CryptoSys PKI DLL was last compiled.
public static string CompileTime()
Public Shared Function CompileTime As String
VB6/C equivalent: PKI_CompileTime
Return the error code of the first error that occurred when calling the last function.
public static int ErrorCode()
Public Shared Function ErrorCode As Integer
VB6/C equivalent: PKI_ErrorCode
Return a description of an error code.
public static string ErrorLookup( int errCode )
Public Shared Function ErrorLookup ( _ errCode As Integer _ ) As String
VB6/C equivalent: PKI_ErrorLookup
Return an error message string for the last error.
public static string FormatErrorMessage( int errCode, string userMsg )
Public Shared Function FormatErrorMessage ( _ errCode As Integer, _ userMsg As String _ ) As String
Retrieve the last error message set by the toolkit.
public static string LastError()
Public Shared Function LastError As String
VB6/C equivalent: PKI_LastError
Return licence type.
public static char LicenceType()
Public Shared Function LicenceType As Char
VB6/C equivalent: PKI_LicenceType
Get additional information about the core DLL module.
public static string ModuleInfo()
Public Shared Function ModuleInfo As String
VB6/C equivalent: PKI_ModuleInfo
Return full path name of core CryptoSys PKI DLL module.
public static string ModuleName()
Public Shared Function ModuleName As String
VB6/C equivalent: PKI_ModuleName
Return the version of this .NET module.
public static string NetVersion()
Public Shared Function NetVersion As String
Return the platform the core DLL was compiled for.
public static string Platform()
Public Shared Function Platform As String
VB6/C equivalent: PKI_Platform
Perform FIPS-140-2 start-up tests.
public static int PowerUpTests()
Public Shared Function PowerUpTests As Integer
VB6/C equivalent: PKI_PowerUpTests
Return the release version of the core CryptoSys PKI DLL as an integer value.
public static int Version()
Public Shared Function Version As Integer
VB6/C equivalent: PKI_Version
Create hash digest in byte format of byte input.
public static byte[] BytesFromBytes( byte[] message, HashAlgorithm hashAlg )
Public Shared Function BytesFromBytes ( _ message As Byte(), _ hashAlg As HashAlgorithm _ ) As Byte()
VB6/C equivalent: HASH_Bytes
Create hash digest of a binary file.
public static byte[] BytesFromFile( string fileName, HashAlgorithm hashAlg )
Public Shared Function BytesFromFile ( _ fileName As String, _ hashAlg As HashAlgorithm _ ) As Byte()
VB6/C equivalent: HASH_File
Create double hash, i.e. hash of hash, in byte format of byte input.
public static byte[] Double( byte[] message, HashAlgorithm hashAlg )
Public Shared Function Double ( _ message As Byte(), _ hashAlg As HashAlgorithm _ ) As Byte()
VB6/C equivalent: HASH_Bytes
Create hash digest in hex format of byte input.
public static string HexFromBytes( byte[] message, HashAlgorithm hashAlg )
Public Shared Function HexFromBytes ( _ message As Byte(), _ hashAlg As HashAlgorithm _ ) As String
VB6/C equivalent: HASH_HexFromBytes
Create hash digest in hex format of a binary file.
public static string HexFromFile( string fileName, HashAlgorithm hashAlg )
Public Shared Function HexFromFile ( _ fileName As String, _ hashAlg As HashAlgorithm _ ) As String
VB6/C equivalent: HASH_HexFromFile
Create hash digest in hex format of hex-encoded input.
public static string HexFromHex( string messageHex, HashAlgorithm hashAlg )
Public Shared Function HexFromHex ( _ messageHex As String, _ hashAlg As HashAlgorithm _ ) As String
VB6/C equivalent: HASH_HexFromHex
Create hash digest in hex format of string input.
public static string HexFromString( string message, HashAlgorithm hashAlg )
Public Shared Function HexFromString ( _ message As String, _ hashAlg As HashAlgorithm _ ) As String
VB6/C equivalent: HASH_HexFromBytes
Create hash digest in hex format of a text file, treating CR-LF (0x13, 0x10) pairs as a single LF (0x10).
public static string HexFromTextFile( string fileName, HashAlgorithm hashAlg )
Public Shared Function HexFromTextFile ( _ fileName As String, _ hashAlg As HashAlgorithm _ ) As String
VB6/C equivalent: HASH_HexFromFile
Return length of message digest output in bytes.
public static int Length( HashAlgorithm hashAlg )
Public Shared Function Length ( _ hashAlg As HashAlgorithm _ ) As Integer
VB6/C equivalent: HASH_Length
Create a keyed-hash HMAC in byte format from byte input.
public static byte[] BytesFromBytes( byte[] message, byte[] key, HashAlgorithm hashAlg )
Public Shared Function BytesFromBytes ( _ message As Byte(), _ key As Byte(), _ hashAlg As HashAlgorithm _ ) As Byte()
VB6/C equivalent: HMAC_Bytes
Create a keyed-hash HMAC in hex-encoded format from byte input.
public static string HexFromBytes( byte[] message, byte[] key, HashAlgorithm hashAlg )
Public Shared Function HexFromBytes ( _ message As Byte(), _ key As Byte(), _ hashAlg As HashAlgorithm _ ) As String
VB6/C equivalent: HMAC_HexFromBytes
Create a keyed-hash HMAC in hex-encoded format from hex-encoded input.
public static string HexFromHex( string messageHex, string keyHex, HashAlgorithm hashAlg )
Public Shared Function HexFromHex ( _ messageHex As String, _ keyHex As String, _ hashAlg As HashAlgorithm _ ) As String
VB6/C equivalent: HMAC_HexFromHex
Derive an EC private key in a deterministic manner from input keying material using the DeriveKeyPair algorithm in RFC9180.
public static string DerivePrivateKey( byte[] ikm, Hpke.CurveName curveName, Hpke.OutputOpts opts )
Public Shared Function DerivePrivateKey ( _ ikm As Byte(), _ curveName As Hpke.CurveName, _ opts As Hpke.OutputOpts _ ) As String
| EC curve | KDF |
|---|---|
| P-256 | HKDF-SHA256 |
| P-384 | HKDF-SHA384 |
| P-521 | HKDF-SHA512 |
| X25519 | HKDF-SHA256 |
| X448 | HKDF-SHA512 |
string ikmhex = "7268600d403fce431561aef583ee1613527cff655c1343f29812e66706df3234"; string skhex = Hpke.DerivePrivateKey(Cnv.FromHex(ikmhex), Hpke.CurveName.X25519, Hpke.OutputOpts.KeyAsHex); // 52c4a758a802cd8b936eceea314432798d5baf2d7e9235dc084ab1b9cfa2f736
VB6/C equivalent: HPKE_DerivePrivateKey
Compute the output of the LabeledExpand function as defined in RFC9180.
public static byte[] LabeledExpand( int numBytes, byte[] prk, string label, byte[] info, Hpke.CurveName curveName, Hpke.AeadAlg aeadAlg )
Public Shared Function LabeledExpand ( _ numBytes As Integer, _ prk As Byte(), _ label As String, _ info As Byte(), _ curveName As Hpke.CurveName, _ aeadAlg As Hpke.AeadAlg _ ) As Byte()
int Nk = 16; // key = LabeledExpand(secret, 'key', key_schedule_context, Nk) byte[] key = Hpke.LabeledExpand(Nk, Cnv.FromHex("12fff91991e93b48de37e7daddb52981084bd8aa64289c3788471d9a9712f397"), "key", Cnv.FromHex("00725611c9d98c07c03f60095cd32d400d8347d45ed67097bbad50fc56da742d07cb6cffde367bb0565ba28bb02c90744a20f5ef37f30523526106f637abb05449"), Hpke.CurveName.X25519, Hpke.AeadAlg.Aes_128_Gcm); // 4531685d41d65f03dc48f6b8302c05b0
VB6/C equivalent: HPKE_LabeledExpand
Compute the output of the LabeledExtract function as defined in RFC9180.
public static byte[] LabeledExtract( byte[] salt, string label, byte[] ikm, Hpke.CurveName curveName, Hpke.AeadAlg aeadAlg )
Public Shared Function LabeledExtract ( _ salt As Byte(), _ label As String, _ ikm As Byte(), _ curveName As Hpke.CurveName, _ aeadAlg As Hpke.AeadAlg _ ) As Byte()
// Used inside KEM string ikmhex = "7268600d403fce431561aef583ee1613527cff655c1343f29812e66706df3234"; Console.WriteLine(Cnv.ToHex(Hpke.LabeledExtract(null, "dkp_prk", Cnv.FromHex(ikmhex), Hpke.CurveName.X25519))); // 7B8BFE1D6F3D0CB45C585E133299C64AC998BF46CAF2DC13BA874F23413EC23A // Used outside KEM Console.WriteLine(Cnv.ToHex(Hpke.LabeledExtract(null, "psk_id_hash", null, Hpke.CurveName.X25519, Hpke.AeadAlg.Aes_128_Gcm))); // 725611C9D98C07C03F60095CD32D400D8347D45ED67097BBAD50FC56DA742D07
VB6/C equivalent: HPKE_LabeledExtract
Generate a key-encryption key (KEK) from input keying material (IKM) using a key derivation function (KDF).
public static byte[] Bytes( int dkLen, byte[] ikm, Kdf.KdfAlg kdfAlg, Kdf.HashAlg hashAlg, byte[] sharedInfo, string paramString )
Public Shared Function Bytes ( _ dkLen As Integer, _ ikm As Byte(), _ kdfAlg As Kdf.KdfAlg, _ hashAlg As Kdf.HashAlg, _ sharedInfo As Byte(), _ paramString As String _ ) As Byte()
VB6/C equivalent: KDF_Bytes
Generate a key-encryption key (KEK) for ECDH key exchange in a CMS EnvelopedData object.
public static byte[] ForCms( byte[] zz, Kdf.KeyWrapAlg keyWrapAlg, Kdf.KdfAlg kdfAlg, Kdf.HashAlg hashAlg, byte[] ukm )
Public Shared Function ForCms ( _ zz As Byte(), _ keyWrapAlg As Kdf.KeyWrapAlg, _ kdfAlg As Kdf.KdfAlg, _ hashAlg As Kdf.HashAlg, _ ukm As Byte() _ ) As Byte()
VB6/C equivalent: KDF_ForCms
Create an Online Certification Status Protocol (OCSP) request as a base64 string.
public static string MakeRequest( string issuerCert, string certFileOrSerialNumber, HashAlgorithm hashAlg )
Public Shared Function MakeRequest ( _ issuerCert As String, _ certFileOrSerialNumber As String, _ hashAlg As HashAlgorithm _ ) As String
VB6/C equivalent: OCSP_MakeRequest
Read a response to an Online Certification Status Protocol (OCSP) request and outputs the main results in text form.
public static string ReadResponse( string responseFile, string issuerCert )
Public Shared Function ReadResponse ( _ responseFile As String, _ issuerCert As String _ ) As String
VB6/C equivalent: OCSP_ReadResponse
Derive a key of any length from a password using the PBKDF2 algorithm from PKCS #5 v2.1.
public static byte[] Kdf2( int dkLen, byte[] pwdBytes, byte[] salt, int count, HashAlgorithm hashAlg )
Public Shared Function Kdf2 ( _ dkLen As Integer, _ pwdBytes As Byte(), _ salt As Byte(), _ count As Integer, _ hashAlg As HashAlgorithm _ ) As Byte()
VB6/C equivalent: PBE_Kdf2
Derive a key in hex format of any length from a password with the salt in hex format.
public static string Kdf2( int dkLen, string pwdStr, string saltHex, int count, HashAlgorithm hashAlg )
Public Shared Function Kdf2 ( _ dkLen As Integer, _ pwdStr As String, _ saltHex As String, _ count As Integer, _ hashAlg As HashAlgorithm _ ) As String
VB6/C equivalent: PBE_Kdf2Hex
Derives a key of any length from a password using the SCRYPT algorithm.
public static byte[] Scrypt( int dkLen, byte[] pwdBytes, byte[] salt, int N, int r, int p )
Public Shared Function Scrypt ( _ dkLen As Integer, _ pwdBytes As Byte(), _ salt As Byte(), _ N As Integer, _ r As Integer, _ p As Integer _ ) As Byte()
VB6/C equivalent: PBE_Scrypt
Derives a key in hex format from a password with the salt in hex format
public static string Scrypt( int dkLen, string pwdStr, string saltHex, int N, int r, int p )
Public Shared Function Scrypt ( _ dkLen As Integer, _ pwdStr As String, _ saltHex As String, _ N As Integer, _ r As Integer, _ p As Integer _ ) As String
string keyHex = Pbe.Scrypt(64, "password", "4E61436C", 1024, 8, 16);
VB6/C equivalent: PBE_ScryptHex
Create a PEM file from a binary file with option for line endings.
public static int FileFromBinFile( string fileToMake, string fileIn, string header, int lineLen, bool unixEOL )
Public Shared Function FileFromBinFile ( _ fileToMake As String, _ fileIn As String, _ header As String, _ lineLen As Integer, _ unixEOL As Boolean _ ) As Integer
VB6/C equivalent: PEM_FileFromBinFile
Convert the contents of a PEM file into a binary file.
public static int FileToBinFile( string fileToMake, string fileIn )
Public Shared Function FileToBinFile ( _ fileToMake As String, _ fileIn As String _ ) As Integer
VB6/C equivalent: PEM_FileToBinFile
Create a PFX (PKCS-12) file from an X.509 certificate and (optional) encrypted private key file with advanced options.
public static int MakeFile( string fileToMake, string certFile, string privateKeyFile, string password, string friendlyName, Pfx.Options pfxOptions )
Public Shared Function MakeFile ( _ fileToMake As String, _ certFile As String, _ privateKeyFile As String, _ password As String, _ friendlyName As String, _ pfxOptions As Pfx.Options _ ) As Integer
VB6/C equivalent: PFX_MakeFile
Verify the MacData signature in a PKCS-12 file.
public static bool SignatureIsValid( string fileName, string password )
Public Shared Function SignatureIsValid ( _ fileName As String, _ password As String _ ) As Boolean
VB6/C equivalent: PFX_VerifySig
Generate output bytes using a pseudorandom function (PRF).
public static byte[] Bytes( int numBytes, byte[] message, byte[] key, Prf.Alg prfAlg, string customStr )
Public Shared Function Bytes ( _ numBytes As Integer, _ message As Byte(), _ key As Byte(), _ prfAlg As Prf.Alg, _ customStr As String _ ) As Byte()
VB6/C equivalent: PRF_Bytes
Open a dialog box to receive a password with user-supplied prompt.
public static string Prompt( int maxChars, string caption, string prompt )
Public Shared Function Prompt ( _ maxChars As Integer, _ caption As String, _ prompt As String _ ) As String
VB6/C equivalent: PWD_Prompt
Generate an array of random bytes.
public static byte[] Bytes( int numBytes )
Public Shared Function Bytes ( _ numBytes As Integer _ ) As Byte()
VB6/C equivalent: RNG_Bytes
Generate an array of random bytes with user-supplied entropy.
public static byte[] Bytes( int numBytes, byte[] arrSeed )
Public Shared Function Bytes ( _ numBytes As Integer, _ arrSeed As Byte() _ ) As Byte()
VB6/C equivalent: RNG_Bytes
Generate an array of random bytes with user-supplied entropy.
public static byte[] Bytes( int numBytes, string seedStr )
Public Shared Function Bytes ( _ numBytes As Integer, _ seedStr As String _ ) As Byte()
VB6/C equivalent: RNG_Bytes
Generate an array of random bytes with a prompt for random keyboard input.
public static byte[] BytesWithPrompt( int numBytes, Rng.Strength strength )
Public Shared Function BytesWithPrompt ( _ numBytes As Integer, _ strength As Rng.Strength _ ) As Byte()
VB6/C equivalent: RNG_BytesWithPrompt
Generate an array of random bytes with a prompt for random keyboard input.
public static byte[] BytesWithPrompt( int numBytes, string prompt, Rng.Strength strength )
Public Shared Function BytesWithPrompt ( _ numBytes As Integer, _ prompt As String, _ strength As Rng.Strength _ ) As Byte()
VB6/C equivalent: RNG_BytesWithPrompt
Generate a random 36-character Global Unique IDentifier (GUID) string according to [RFC4122].
public static string Guid()
Public Shared Function Guid As String
VB6/C equivalent: RNG_Guid
Initialize the RNG generator with a seed file.
public static bool Initialize( string seedFile )
Public Shared Function Initialize ( _ seedFile As String _ ) As Boolean
VB6/C equivalent: RNG_Initialize
Query and initialize the RNG generator using Intel(R) DRNG, if available.
public static int InitializeEx( Rng.Options opts )
Public Shared Function InitializeEx ( _ opts As Rng.Options _ ) As Integer
VB6/C equivalent: RNG_Initialize
Create a new seed file suitable for use with Rng.Initialize.
public static bool MakeSeedFile( string seedFile, Rng.Strength strength )
Public Shared Function MakeSeedFile ( _ seedFile As String, _ strength As Rng.Strength _ ) As Boolean
VB6/C equivalent: RNG_MakeSeedFile
Generate a random number (integer) in a given range.
public static int Number( int lower, int upper )
Public Shared Function Number ( _ lower As Integer, _ upper As Integer _ ) As Integer
VB6/C equivalent: RNG_Number
Generate a single random octet (byte).
public static byte Octet()
Public Shared Function Octet As Byte
VB6/C equivalent: RNG_Number
Carry out a NIST SP800-90 health check and FIPS140-2 statistical tests on the random number generator.
public static bool Test( string resultFile )
Public Shared Function Test ( _ resultFile As String _ ) As Boolean
VB6/C equivalent: RNG_Test
Test the RNG for conformance to NIST SP800-90A using the relevant test specified in DRBGVS.
public static string TestDrbgvs( int returnedBitsLen, string entropyInput, string nonce, string personalizationString, string additionalInput1, string entropyReseed, string additionalInputReseed, string additionalInput2 )
Public Shared Function TestDrbgvs ( _ returnedBitsLen As Integer, _ entropyInput As String, _ nonce As String, _ personalizationString As String, _ additionalInput1 As String, _ entropyReseed As String, _ additionalInputReseed As String, _ additionalInput2 As String _ ) As String
VB6/C equivalent: RNG_TestDRBGVS
Update the RNG seed file.
public static bool UpdateSeedFile( string seedFile )
Public Shared Function UpdateSeedFile ( _ seedFile As String _ ) As Boolean
VB6/C equivalent: RNG_UpdateSeedFile
Check the validity of an "internal" RSA public or private key.
public static int CheckKey( string intKeyString )
Public Shared Function CheckKey ( _ intKeyString As String _ ) As Integer
VB6/C equivalent: RSA_CheckKey
Check the validity of an "internal" RSA public or private key.
public static int CheckKey( StringBuilder sbKeyString )
Public Shared Function CheckKey ( _ sbKeyString As StringBuilder _ ) As Integer
VB6/C equivalent: RSA_CheckKey
Decode an encoded message for signature.
public static byte[] DecodeDigestForSignature( byte[] data, bool getFullDigestInfo )
Public Shared Function DecodeDigestForSignature ( _ data As Byte(), _ getFullDigestInfo As Boolean _ ) As Byte()
VB6/C equivalent: RSA_DecodeMsg
Decode a message for encryption.
public static byte[] DecodeMsgForEncryption( byte[] data, Rsa.EME method )
Public Shared Function DecodeMsgForEncryption ( _ data As Byte(), _ method As Rsa.EME _ ) As Byte()
VB6/C equivalent: RSA_DecodeMsg
Decode a message padded using ISO/IEC 9796-1 formatting.
public static byte[] DecodeMsgIso9796( byte[] data, int keyBits )
Public Shared Function DecodeMsgIso9796 ( _ data As Byte(), _ keyBits As Integer _ ) As Byte()
VB6/C equivalent: RSA_DecodeMsg
Decrypt a message encrypted using an RSA encryption scheme.
public static byte[] Decrypt( byte[] data, string privateKeyFile, string password, Rsa.EME method, Rsa.HashAlg hashAlg, Rsa.AdvOptions advOpts )
Public Shared Function Decrypt ( _ data As Byte(), _ privateKeyFile As String, _ password As String, _ method As Rsa.EME, _ hashAlg As Rsa.HashAlg, _ advOpts As Rsa.AdvOptions _ ) As Byte()
VB6/C equivalent: RSA_Decrypt
Encode a message digest for signature.
public static byte[] EncodeDigestForSignature( int keyBytes, byte[] digest, HashAlgorithm hashAlg )
Public Shared Function EncodeDigestForSignature ( _ keyBytes As Integer, _ digest As Byte(), _ hashAlg As HashAlgorithm _ ) As Byte()
VB6/C equivalent: RSA_EncodeMsg
Encode a message for encryption.
public static byte[] EncodeMsgForEncryption( int keyBytes, byte[] message, Rsa.EME method )
Public Shared Function EncodeMsgForEncryption ( _ keyBytes As Integer, _ message As Byte(), _ method As Rsa.EME _ ) As Byte()
VB6/C equivalent: RSA_EncodeMsg
Encode a message for signature.
public static byte[] EncodeMsgForSignature( int keyBytes, byte[] message, HashAlgorithm hashAlg )
Public Shared Function EncodeMsgForSignature ( _ keyBytes As Integer, _ message As Byte(), _ hashAlg As HashAlgorithm _ ) As Byte()
VB6/C equivalent: RSA_EncodeMsg
Encode a message using ISO/IEC 9796-1 formatting.
public static byte[] EncodeMsgIso9796( byte[] message, int keyBits )
Public Shared Function EncodeMsgIso9796 ( _ message As Byte(), _ keyBits As Integer _ ) As Byte()
VB6/C equivalent: RSA_EncodeMsg
Encrypt a short message using RSA encryption.
public static byte[] Encrypt( byte[] data, string publicKeyFile, Rsa.EME method, Rsa.HashAlg hashAlg, Rsa.AdvOptions advOpts )
Public Shared Function Encrypt ( _ data As Byte(), _ publicKeyFile As String, _ method As Rsa.EME, _ hashAlg As Rsa.HashAlg, _ advOpts As Rsa.AdvOptions _ ) As Byte()
VB6/C equivalent: RSA_Encrypt
Create an RSA key string in internal format from an XML string.
public static string FromXMLString( string xmlString )
Public Shared Function FromXMLString ( _ xmlString As String _ ) As String
VB6/C equivalent: RSA_FromXMLString
Create an RSA key string in internal format from an XML string with options.
public static string FromXMLString( string xmlString, Rsa.XmlOptions options )
Public Shared Function FromXMLString ( _ xmlString As String, _ options As Rsa.XmlOptions _ ) As String
VB6/C equivalent: RSA_FromXMLString
Create an RSA key string in internal format from an XML string with flag to exclude private key details.
public static string FromXMLString( string xmlString, bool excludePrivateParams )
Public Shared Function FromXMLString ( _ xmlString As String, _ excludePrivateParams As Boolean _ ) As String
VB6/C equivalent: RSA_FromXMLString
Extract an encrypted private key from a PKCS-12 PKCS8ShroudedKeyBag, saving the output directly as a new file.
public static int GetPrivateKeyFromPFX( string outputFile, string pfxFile )
Public Shared Function GetPrivateKeyFromPFX ( _ outputFile As String, _ pfxFile As String _ ) As Integer
VB6/C equivalent: RSA_GetPrivateKeyFromPFX
Read public key from X.509 certificate into internal string format.
[ObsoleteAttribute("Use Rsa.ReadPublicKey() instead", false)] public static StringBuilder GetPublicKeyFromCert( string certFile )
<ObsoleteAttribute("Use Rsa.ReadPublicKey() instead", False)> _ Public Shared Function GetPublicKeyFromCert ( _ certFile As String _ ) As StringBuilder
VB6/C equivalent: RSA_GetPublicKeyFromCert
Return number of significant bits in RSA key modulus.
public static int KeyBits( string strRsaKey )
Public Shared Function KeyBits ( _ strRsaKey As String _ ) As Integer
VB6/C equivalent: RSA_KeyBits
Return number of significant bits in RSA key modulus.
public static int KeyBits( StringBuilder sbRsaKey )
Public Shared Function KeyBits ( _ sbRsaKey As StringBuilder _ ) As Integer
VB6/C equivalent: RSA_KeyBits
Return number of bytes (octets) in RSA key modulus.
public static int KeyBytes( string strRsaKey )
Public Shared Function KeyBytes ( _ strRsaKey As String _ ) As Integer
VB6/C equivalent: RSA_KeyBytes
Return number of bytes (octets) in RSA key modulus.
public static int KeyBytes( StringBuilder sbRsaKey )
Public Shared Function KeyBytes ( _ sbRsaKey As StringBuilder _ ) As Integer
VB6/C equivalent: RSA_KeyBytes
Compute the hash code of an "internal" RSA public or private key string.
public static int KeyHashCode( string intKeyString )
Public Shared Function KeyHashCode ( _ intKeyString As String _ ) As Integer
VB6/C equivalent: RSA_KeyHashCode
Compute the hash code of an "internal" RSA public or private key string.
public static int KeyHashCode( StringBuilder sbKeyString )
Public Shared Function KeyHashCode ( _ sbKeyString As StringBuilder _ ) As Integer
VB6/C equivalent: RSA_KeyHashCode
Verify that a pair of "internal" RSA private and public key strings are matched.
public static int KeyMatch( string privateKey, string publicKey )
Public Shared Function KeyMatch ( _ privateKey As String, _ publicKey As String _ ) As Integer
VB6/C equivalent: RSA_KeyMatch
Verify that a pair of "internal" RSA private and public key strings are matched.
public static int KeyMatch( StringBuilder sbPrivateKey, StringBuilder sbPublicKey )
Public Shared Function KeyMatch ( _ sbPrivateKey As StringBuilder, _ sbPublicKey As StringBuilder _ ) As Integer
VB6/C equivalent: RSA_KeyMatch
Extract a base64-encoded RSA key value from internal key string
public static string KeyValue( string keyString, string fieldName )
Public Shared Function KeyValue ( _ keyString As String, _ fieldName As String _ ) As String
VB6/C equivalent: RSA_KeyValue
Generate an RSA public/private key pair with extended options for encrypting private key [DEPRECATED].
[ObsoleteAttribute("Use Rsa.MakeKeys(String, String, String, Int32, Rsa.PublicExponent, Rsa.PbeOptions, String, Rsa.Format, Boolean) instead", false)] public static int MakeKeys( string publicKeyFile, string privateKeyFile, int bits, Rsa.PublicExponent exponent, int iterCount, string password, CipherAlgorithm cipherAlg, HashAlgorithm hashAlg, Rsa.Format fileFormat, bool showProgress )
<ObsoleteAttribute("Use Rsa.MakeKeys(String, String, String, Int32, Rsa.PublicExponent, Rsa.PbeOptions, String, Rsa.Format, Boolean) instead", _ False)> _ Public Shared Function MakeKeys ( _ publicKeyFile As String, _ privateKeyFile As String, _ bits As Integer, _ exponent As Rsa.PublicExponent, _ iterCount As Integer, _ password As String, _ cipherAlg As CipherAlgorithm, _ hashAlg As HashAlgorithm, _ fileFormat As Rsa.Format, _ showProgress As Boolean _ ) As Integer
VB6/C equivalent: RSA_MakeKeys
Generate an RSA public/private key pair [DEPRECATED].
[ObsoleteAttribute("Use Rsa.MakeKeys(String, String, String, Int32, Rsa.PublicExponent, Rsa.PbeOptions, String, Rsa.Format, Boolean) instead", false)] public static int MakeKeys( string publicKeyFile, string privateKeyFile, int bits, Rsa.PublicExponent exponent, int iterCount, string password, Rsa.PbeOptions cryptOption, bool showProgress, byte[] seedBytes )
<ObsoleteAttribute("Use Rsa.MakeKeys(String, String, String, Int32, Rsa.PublicExponent, Rsa.PbeOptions, String, Rsa.Format, Boolean) instead", _ False)> _ Public Shared Function MakeKeys ( _ publicKeyFile As String, _ privateKeyFile As String, _ bits As Integer, _ exponent As Rsa.PublicExponent, _ iterCount As Integer, _ password As String, _ cryptOption As Rsa.PbeOptions, _ showProgress As Boolean, _ seedBytes As Byte() _ ) As Integer
VB6/C equivalent: RSA_MakeKeys
Generate an RSA public/private key pair.
public static int MakeKeys( string publicKeyFile, string privateKeyFile, string password, int bits, Rsa.PublicExponent exponent, Rsa.PbeOptions pbes, string paramString, Rsa.Format fileFormat, bool showProgress )
Public Shared Function MakeKeys ( _ publicKeyFile As String, _ privateKeyFile As String, _ password As String, _ bits As Integer, _ exponent As Rsa.PublicExponent, _ pbes As Rsa.PbeOptions, _ paramString As String, _ fileFormat As Rsa.Format, _ showProgress As Boolean _ ) As Integer
Valid name-value pairs for paramString are:
| count=integer | To set the iteration count used in the PBKDF2 method, e.g. "count=5000;" [default=2048]. |
| prf=hmac-name | To change the HMAC algorithm used in the PBKDF2 method, e.g. "prf=hmacwithSHA256;" [default=hmacwithSHA1]. |
VB6/C equivalent: RSA_MakeKeysXtd
Convert an internal private key string into a public one.
public static StringBuilder PublicKeyFromPrivate( StringBuilder sbKeyString )
Public Shared Function PublicKeyFromPrivate ( _ sbKeyString As StringBuilder _ ) As StringBuilder
VB6/C equivalent: RSA_PublicKeyFromPrivate
Carry out RSA transformation using private key.
public static byte[] RawPrivate( byte[] data, string privateKeyStr )
Public Shared Function RawPrivate ( _ data As Byte(), _ privateKeyStr As String _ ) As Byte()
VB6/C equivalent: RSA_RawPrivate
Carry out RSA transformation using private key (with specialist options).
public static byte[] RawPrivate( byte[] data, string privateKeyStr, int options )
Public Shared Function RawPrivate ( _ data As Byte(), _ privateKeyStr As String, _ options As Integer _ ) As Byte()
VB6/C equivalent: RSA_RawPrivate
Carry out RSA transformation using public key.
public static byte[] RawPublic( byte[] data, string publicKeyStr )
Public Shared Function RawPublic ( _ data As Byte(), _ publicKeyStr As String _ ) As Byte()
VB6/C equivalent: RSA_RawPublic
Carry out RSA transformation using public key (with specialist options).
public static byte[] RawPublic( byte[] data, string publicKeyStr, int options )
Public Shared Function RawPublic ( _ data As Byte(), _ publicKeyStr As String, _ options As Integer _ ) As Byte()
VB6/C equivalent: RSA_RawPublic
Read encrypted private key file into internal string format.
[ObsoleteAttribute("Use Rsa.ReadPrivateKey() instead", false)] public static StringBuilder ReadEncPrivateKey( string privateKeyFile, string password )
<ObsoleteAttribute("Use Rsa.ReadPrivateKey() instead", False)> _ Public Shared Function ReadEncPrivateKey ( _ privateKeyFile As String, _ password As String _ ) As StringBuilder
VB6/C equivalent: RSA_ReadEncPrivateKey
Read from a file or string containing a private key into an "internal" private key string.
public static StringBuilder ReadPrivateKey( string privateKeyFile, string password )
Public Shared Function ReadPrivateKey ( _ privateKeyFile As String, _ password As String _ ) As StringBuilder
VB6/C equivalent: RSA_ReadAnyPrivateKey
Read a private key directly from an encrypted PFX/PKCS-12 file into an "internal" private key string.
[ObsoleteAttribute("Use Rsa.ReadPrivateKey() instead", false)] public static StringBuilder ReadPrivateKeyFromPFX( string pfxFile, string password )
<ObsoleteAttribute("Use Rsa.ReadPrivateKey() instead", False)> _ Public Shared Function ReadPrivateKeyFromPFX ( _ pfxFile As String, _ password As String _ ) As StringBuilder
VB6/C equivalent: RSA_ReadPrivateKeyFromPFX
Read from an (unencrypted) PKCS-8 private key info file into a private key string.
[ObsoleteAttribute("Use Rsa.ReadPrivateKey() instead", false)] public static StringBuilder ReadPrivateKeyInfo( string prikeyinfoFile )
<ObsoleteAttribute("Use Rsa.ReadPrivateKey() instead", False)> _ Public Shared Function ReadPrivateKeyInfo ( _ prikeyinfoFile As String _ ) As StringBuilder
VB6/C equivalent: RSA_ReadPrivateKeyInfo
Read from a file or string containing a public key into an "internal" public key string.
public static StringBuilder ReadPublicKey( string certOrPublicKeyFile )
Public Shared Function ReadPublicKey ( _ certOrPublicKeyFile As String _ ) As StringBuilder
VB6/C equivalent: RSA_ReadPublicKey
Save an internal RSA key string to an encrypted key file.
public static int SaveEncKey( string outputFile, string privateKey, string password, Rsa.PbeOptions pbeOption, string paramString, Rsa.Format format )
Public Shared Function SaveEncKey ( _ outputFile As String, _ privateKey As String, _ password As String, _ pbeOption As Rsa.PbeOptions, _ paramString As String, _ format As Rsa.Format _ ) As Integer
Valid name-value pairs for paramString are:
| count=integer | To set the iteration count used in the PBKDF2 method, e.g. "count=5000;" [default=2048]. |
| prf=hmac-name | To change the HMAC algorithm used in the PBKDF2 method, e.g. "prf=hmacwithSHA256;" [default=hmacwithSHA1]. |
VB6/C equivalent: RSA_SaveEncKey
Save a private key string to a PKCS-8 EncryptedPrivateKeyInfo file using PBES2 algorithm [DEPRECATED].
public static int SaveEncPrivateKey( string outputFile, string privateKey, int iterationCount, string password, CipherAlgorithm cipherAlg, HashAlgorithm hashAlg, Rsa.Format format )
Public Shared Function SaveEncPrivateKey ( _ outputFile As String, _ privateKey As String, _ iterationCount As Integer, _ password As String, _ cipherAlg As CipherAlgorithm, _ hashAlg As HashAlgorithm, _ format As Rsa.Format _ ) As Integer
VB6/C equivalent: RSA_SaveEncPrivateKey
Save a private key string to a PKCS-8 EncryptedPrivateKeyInfo file [DEPRECATED].
public static int SaveEncPrivateKey( string outputFile, string privateKey, int iterationCount, string password, Rsa.PbeOptions pbeOption, Rsa.Format format )
Public Shared Function SaveEncPrivateKey ( _ outputFile As String, _ privateKey As String, _ iterationCount As Integer, _ password As String, _ pbeOption As Rsa.PbeOptions, _ format As Rsa.Format _ ) As Integer
VB6/C equivalent: RSA_SaveEncPrivateKey
Save a private key string to an (unencrypted) PKCS-8 private key info file.
public static int SavePrivateKeyInfo( string outputFile, string privateKey, Rsa.Format format )
Public Shared Function SavePrivateKeyInfo ( _ outputFile As String, _ privateKey As String, _ format As Rsa.Format _ ) As Integer
VB6/C equivalent: RSA_SavePrivateKeyInfo
Save a public key string to PKCS-1 public key file.
public static int SavePublicKey( string outputFile, string publicKey, Rsa.Format format )
Public Shared Function SavePublicKey ( _ outputFile As String, _ publicKey As String, _ format As Rsa.Format _ ) As Integer
VB6/C equivalent: RSA_SavePublicKey
Create an XML string representation of an RSA internal key string.
public static string ToXMLString( string intKeyString, Rsa.XmlOptions options )
Public Shared Function ToXMLString ( _ intKeyString As String, _ options As Rsa.XmlOptions _ ) As String
VB6/C equivalent: RSA_ToXMLString
Create an XML string representation of an RSA internal key string with option to add a namespace prefix.
public static string ToXMLString( string intKeyString, string prefix, Rsa.XmlOptions options )
Public Shared Function ToXMLString ( _ intKeyString As String, _ prefix As String, _ options As Rsa.XmlOptions _ ) As String
VB6/C equivalent: RSA_ToXMLStringEx
Get the hash algorithm used in the signature algorithm.
public static HashAlgorithm GetHashAlgFromSigAlg( SigAlgorithm sigAlg )
Public Shared Function GetHashAlgFromSigAlg ( _ sigAlg As SigAlgorithm _ ) As HashAlgorithm
Compute a signature value over data in a byte array.
public static string SignData( byte[] data, string privateKeyFile, string password, SigAlgorithm sigAlg, Sig.SigOptions sigOpts, Sig.Encoding sigEncoding )
Public Shared Function SignData ( _ data As Byte(), _ privateKeyFile As String, _ password As String, _ sigAlg As SigAlgorithm, _ sigOpts As Sig.SigOptions, _ sigEncoding As Sig.Encoding _ ) As String
VB6/C equivalent: SIG_SignData
Compute a signature value over a message digest value.
public static string SignDigest( byte[] digest, string privateKeyFile, string password, SigAlgorithm sigAlg, Sig.SigOptions sigOpts, Sig.Encoding sigEncoding )
Public Shared Function SignDigest ( _ digest As Byte(), _ privateKeyFile As String, _ password As String, _ sigAlg As SigAlgorithm, _ sigOpts As Sig.SigOptions, _ sigEncoding As Sig.Encoding _ ) As String
VB6/C equivalent: SIG_SignData
Compute a signature value over binary data in a file.
public static string SignFile( string dataFile, string privateKeyFile, string password, SigAlgorithm sigAlg, Sig.SigOptions sigOpts, Sig.Encoding sigEncoding )
Public Shared Function SignFile ( _ dataFile As String, _ privateKeyFile As String, _ password As String, _ sigAlg As SigAlgorithm, _ sigOpts As Sig.SigOptions, _ sigEncoding As Sig.Encoding _ ) As String
VB6/C equivalent: SIG_SignFile
Verify a signature value over data in a byte array.
public static int VerifyData( string sigStr, byte[] data, string certOrKeyFile, SigAlgorithm sigAlg, Sig.VerifyOpts opts )
Public Shared Function VerifyData ( _ sigStr As String, _ data As Byte(), _ certOrKeyFile As String, _ sigAlg As SigAlgorithm, _ opts As Sig.VerifyOpts _ ) As Integer
VB6/C equivalent: SIG_VerifyData
Verify a signature value over a message digest value of data.
public static int VerifyDigest( string sigStr, byte[] digest, string certOrKeyFile, SigAlgorithm sigAlg, Sig.VerifyOpts opts )
Public Shared Function VerifyDigest ( _ sigStr As String, _ digest As Byte(), _ certOrKeyFile As String, _ sigAlg As SigAlgorithm, _ opts As Sig.VerifyOpts _ ) As Integer
VB6/C equivalent: SIG_VerifyData
Verify a signature value over data in a file.
public static int VerifyFile( string sigStr, string dataFile, string certOrKeyFile, SigAlgorithm sigAlg, Sig.VerifyOpts opts )
Public Shared Function VerifyFile ( _ sigStr As String, _ dataFile As String, _ certOrKeyFile As String, _ sigAlg As SigAlgorithm, _ opts As Sig.VerifyOpts _ ) As Integer
VB6/C equivalent: SIG_VerifyFile
Extract the body from an S/MIME entity.
public static int Extract( string outputFile, string inputFile, Smime.Options opts )
Public Shared Function Extract ( _ outputFile As String, _ inputFile As String, _ opts As Smime.Options _ ) As Integer
VB6/C equivalent: SMIME_Extract
Query an S/MIME entity for selected information.
public static string Query( string inputFile, string query )
Public Shared Function Query ( _ inputFile As String, _ query As String _ ) As String
Valid queries are:
| "content-type" | Value of Content-Type, e.g. "application/pkcs7-mime". |
| "smime-type" | Value of smime-type parameter of Content-Type, e.g. , e.g. "enveloped-data". |
| "encoding" | Value of Content-Transfer-Encoding, e.g. "base64". |
| "name" | Value of name parameter of Content-Type, e.g. "smime.p7m" |
| "filename" | Value of filename parameter of Content-Disposition, e.g. "smime.p7m". |
VB6/C equivalent: SMIME_Query
Wrap a CMS object in an S/MIME entity.
public static int Wrap( string outputFile, string inputFile, Smime.Options opts )
Public Shared Function Wrap ( _ outputFile As String, _ inputFile As String, _ opts As Smime.Options _ ) As Integer
VB6/C equivalent: SMIME_Wrap
Decrypt data in byte array.
public static byte[] Decrypt( byte[] input, byte[] key, Mode mode, byte[] iv )
Public Shared Function Decrypt ( _ input As Byte(), _ key As Byte(), _ mode As Mode, _ iv As Byte() _ ) As Byte()
VB6/C equivalent: TDEA_BytesMode
Decrypt hex-encoded data string.
public static string Decrypt( string inputHex, string keyHex, Mode mode, string ivHex )
Public Shared Function Decrypt ( _ inputHex As String, _ keyHex As String, _ mode As Mode, _ ivHex As String _ ) As String
VB6/C equivalent: TDEA_HexMode
Decrypt encoded data string.
public static string Decrypt( string inputStr, string keyStr, Mode mode, string ivStr, EncodingBase encodingBase )
Public Shared Function Decrypt ( _ inputStr As String, _ keyStr As String, _ mode As Mode, _ ivStr As String, _ encodingBase As EncodingBase _ ) As String
VB6/C equivalent: TDEA_B64Mode
Encrypt data in byte array.
public static byte[] Encrypt( byte[] input, byte[] key, Mode mode, byte[] iv )
Public Shared Function Encrypt ( _ input As Byte(), _ key As Byte(), _ mode As Mode, _ iv As Byte() _ ) As Byte()
VB6/C equivalent: TDEA_BytesMode
Encrypt hex-encoded data string.
public static string Encrypt( string inputHex, string keyHex, Mode mode, string ivHex )
Public Shared Function Encrypt ( _ inputHex As String, _ keyHex As String, _ mode As Mode, _ ivHex As String _ ) As String
VB6/C equivalent: TDEA_HexMode
Encrypt encoded data string.
public static string Encrypt( string inputStr, string keyStr, Mode mode, string ivStr, EncodingBase encodingBase )
Public Shared Function Encrypt ( _ inputStr As String, _ keyStr As String, _ mode As Mode, _ ivStr As String, _ encodingBase As EncodingBase _ ) As String
VB6/C equivalent: TDEA_B64Mode
Decrypt a file.
public static int FileDecrypt( string fileOut, string fileIn, byte[] key, Mode mode, byte[] iv )
Public Shared Function FileDecrypt ( _ fileOut As String, _ fileIn As String, _ key As Byte(), _ mode As Mode, _ iv As Byte() _ ) As Integer
VB6/C equivalent: TDEA_File
Decrypt a file passing key and IV as hex strings.
public static int FileDecrypt( string fileOut, string fileIn, string keyHex, Mode mode, string ivHex )
Public Shared Function FileDecrypt ( _ fileOut As String, _ fileIn As String, _ keyHex As String, _ mode As Mode, _ ivHex As String _ ) As Integer
Encrypt a file.
public static int FileEncrypt( string fileOut, string fileIn, byte[] key, Mode mode, byte[] iv )
Public Shared Function FileEncrypt ( _ fileOut As String, _ fileIn As String, _ key As Byte(), _ mode As Mode, _ iv As Byte() _ ) As Integer
VB6/C equivalent: TDEA_File
Encrypt a file passing key and IV as hex strings.
public static int FileEncrypt( string fileOut, string fileIn, string keyHex, Mode mode, string ivHex )
Public Shared Function FileEncrypt ( _ fileOut As String, _ fileIn As String, _ keyHex As String, _ mode As Mode, _ ivHex As String _ ) As Integer
Zeroise data in memory.
public static bool Data( byte[] data )
Public Shared Function Data ( _ data As Byte() _ ) As Boolean
VB6/C equivalent: WIPE_Data
Securely wipe and delete a file with options.
public static bool File( string fileName, Wipe.Options opts )
Public Shared Function File ( _ fileName As String, _ opts As Wipe.Options _ ) As Boolean
VB6/C equivalent: WIPE_File
Zeroise a StringBuilder.
public static bool String( StringBuilder sb )
Public Shared Function String ( _ sb As StringBuilder _ ) As Boolean
VB6/C equivalent: WIPE_Data
Return date and time certificate expires.
public static string CertExpiresOn( string certFile )
Public Shared Function CertExpiresOn ( _ certFile As String _ ) As String
VB6/C equivalent: X509_CertExpiresOn
Return date and time certificate was issued.
public static string CertIssuedOn( string certFile )
Public Shared Function CertIssuedOn ( _ certFile As String _ ) As String
VB6/C equivalent: X509_CertIssuedOn
Get the issuer name of an X.509 certificate.
public static string CertIssuerName( string certFile, string delimiter )
Public Shared Function CertIssuerName ( _ certFile As String, _ delimiter As String _ ) As String
VB6/C equivalent: X509_CertIssuerName
Verify that an X.509 certificate is currently valid as per system clock.
public static bool CertIsValidNow( string certFile )
Public Shared Function CertIsValidNow ( _ certFile As String _ ) As Boolean
VB6/C equivalent: X509_CertIsValidNow
Create a PKCS #10 certificate signing request (CSR).
public static int CertRequest( string reqFile, string privateKeyFile, string distName, string extensions, string password, SigAlgorithm sigAlg, X509.CsrOptions opts )
Public Shared Function CertRequest ( _ reqFile As String, _ privateKeyFile As String, _ distName As String, _ extensions As String, _ password As String, _ sigAlg As SigAlgorithm, _ opts As X509.CsrOptions _ ) As Integer
VB6/C equivalent: X509_CertRequest
Return serial number in hex format.
public static string CertSerialNumber( string certFile )
Public Shared Function CertSerialNumber ( _ certFile As String _ ) As String
VB6/C equivalent: X509_CertSerialNumber
Get the subject name of an X.509 certificate.
public static string CertSubjectName( string certFile, string delimiter )
Public Shared Function CertSubjectName ( _ certFile As String, _ delimiter As String _ ) As String
VB6/C equivalent: X509_CertSubjectName
Calculate the thumbprint (message digest hash) of an X.509 certificate.
public static string CertThumb( string certFile, HashAlgorithm hashAlg )
Public Shared Function CertThumb ( _ certFile As String, _ hashAlg As HashAlgorithm _ ) As String
VB6/C equivalent: X509_CertThumb
Check whether an X.509 certificate has been revoked in a Certificate Revocation List (CRL).
public static int CheckCertInCRL( string certFile, string crlFile, string issuerCert, string dateStr )
Public Shared Function CheckCertInCRL ( _ certFile As String, _ crlFile As String, _ issuerCert As String, _ dateStr As String _ ) As Integer
VB6/C equivalent: X509_CheckCertInCRL
Return number of certificates in a PKCS-7 "certs-only" certificate chain file.
public static int GetCertCountInP7Chain( string inputFile )
Public Shared Function GetCertCountInP7Chain ( _ inputFile As String _ ) As Integer
VB6/C equivalent: X509_GetCertCountInP7Chain
Extract an X.509 certificate from a PKCS-7 "certs-only" certificate chain file, saving the output directly as a new file.
public static int GetCertFromP7Chain( string outputFile, string inputFile, int index )
Public Shared Function GetCertFromP7Chain ( _ outputFile As String, _ inputFile As String, _ index As Integer _ ) As Integer
VB6/C equivalent: X509_GetCertFromP7Chain
Extract an X.509 certificate from a PKCS-12 PFX/.p12 file, saving the output directly as a new file.
public static int GetCertFromPFX( string outputFile, string inputFile, string password )
Public Shared Function GetCertFromPFX ( _ outputFile As String, _ inputFile As String, _ password As String _ ) As Integer
VB6/C equivalent: X509_GetCertFromPFX
Extract all X.509 certificates from a PKCS-12 PFX/.p12 file, saving the output directly as a new PKCS-7 "certs-only" certificate chain file.
public static int GetP7ChainFromPFX( string outputFile, string inputFile, string password )
Public Shared Function GetP7ChainFromPFX ( _ outputFile As String, _ inputFile As String, _ password As String _ ) As Integer
VB6/C equivalent: X509_GetCertFromPFX
Create a message digest of the Issuer's name and the cert serial number.
public static string HashIssuerAndSN( string certFile, HashAlgorithm algorithm )
Public Shared Function HashIssuerAndSN ( _ certFile As String, _ algorithm As HashAlgorithm _ ) As String
VB6/C equivalent: X509_HashIssuerAndSN
Returns a bitfield containing the keyUsage flags.
public static int KeyUsageFlags( string certFile )
Public Shared Function KeyUsageFlags ( _ certFile As String _ ) As Integer
VB6/C equivalent: X509_KeyUsageFlags
Create a new X.509 certificate using subject's public key and issuer's private key files with signature options.
public static int MakeCert( string certFile, string issuerCert, string subjectPubKeyFile, string issuerPriKeyFile, int certNum, int yearsValid, string distName, string extensions, X509.KeyUsageOptions keyUsageOptions, string password, SigAlgorithm sigAlg, X509.CertOptions options )
Public Shared Function MakeCert ( _ certFile As String, _ issuerCert As String, _ subjectPubKeyFile As String, _ issuerPriKeyFile As String, _ certNum As Integer, _ yearsValid As Integer, _ distName As String, _ extensions As String, _ keyUsageOptions As X509.KeyUsageOptions, _ password As String, _ sigAlg As SigAlgorithm, _ options As X509.CertOptions _ ) As Integer
| rfc822Name=string; | To set the rfc822 email address in the subjectAltName extension, e.g. rfc822Name=myname@testorg.com. |
| serialNumber=hex-digits; | To override the serial number set by certNum with a larger, unlimited integer in hexadecimal format, e.g. serialNumber=12deadbeefcafe0123. |
| subjectKeyIdentifier=hex-digits; | To set the subjectAltName extension with an octet string (binary) value specified in hex format e.g. subjectKeyIdentifier=fedcba9876543210. |
| notAfter=iso-date-string; | To override the validity period set by yearsValid with a specific date and time in ISO format, e.g. notAfter=2020-12-31 or notAfter=2020-12-31T14:03:59. If no time is given it will default to 23:59:59. Note that this time is UTC (GMT) not local. |
| notBefore=iso-date-string; | To override the default start time from one minute ago to a specific date and time in ISO format, e.g. notBefore=2008-12-31. If no time is given it will default to 00:00:01. Note that this time is UTC (GMT) not local. |
| <dotted-oid>=#<hexstring>; | Add an arbitrary X.509 version 3 Extension with typeID set to decoded <dotted-oid> and extnValue set to ASN.1 value encoded in <hexstring>. |
As an alternative, you can create a new X.509 certificate using a PKCS-10 certificate signing request (CSR) file. Pass the name of the CSR file in the subjectPubkeyFile parameter and set the distName empty "". The empty distinguished name parameter is a flag that a CSR file is being used.
VB6/C equivalent: X509_MakeCert
Create a self-signed X.509 certificate with signature options.
public static int MakeCertSelf( string certFile, string privateKeyFile, int certNum, int yearsValid, string distName, string extensions, X509.KeyUsageOptions keyUsageOptions, string password, SigAlgorithm sigAlg, X509.CertOptions options )
Public Shared Function MakeCertSelf ( _ certFile As String, _ privateKeyFile As String, _ certNum As Integer, _ yearsValid As Integer, _ distName As String, _ extensions As String, _ keyUsageOptions As X509.KeyUsageOptions, _ password As String, _ sigAlg As SigAlgorithm, _ options As X509.CertOptions _ ) As Integer
VB6/C equivalent: X509_MakeCertSelf
Create an X.509 Certificate Revocation List (CRL).
public static int MakeCRL( string crlFile, string issuerCert, string issuerKeyFile, string password, string revokedCertList, string extensions, SigAlgorithm sigAlg, X509.CrlOptions opts )
Public Shared Function MakeCRL ( _ crlFile As String, _ issuerCert As String, _ issuerKeyFile As String, _ password As String, _ revokedCertList As String, _ extensions As String, _ sigAlg As SigAlgorithm, _ opts As X509.CrlOptions _ ) As Integer
"1,2007-12-31; 2, 2009-12-31T12:59:59Z; 66000,2066-01-01; #x0102deadbeef,2010-02-28T01:01:59"
By default, the lastUpdate time in the CRL is set to the time given by the system clock, and nextUpdate time is left empty. You can specify your own times using the lastUpdate and nextUpdate attributes in the extensions parameter. Times, if specified, must be in ISO 8601 format and are always interpreted as GMT times whether or not you add a "Z".VB6/C equivalent: X509_MakeCRL
Query an X.509 certificate file for selected information.
public static string QueryCert( string certFile, string query, X509.OutputOpts outOpts )
Public Shared Function QueryCert ( _ certFile As String, _ query As String, _ outOpts As X509.OutputOpts _ ) As String
Valid queries are:
| "version" | X.509 version number, e.g. "3". |
| "serialNumber" | Serial number in hex-encoded format. |
| "signatureAlgorithm" | Signature algorithm used, e.g. "sha1WithRSAEncryption". |
| "signatureValue" | Signature value in hex-encoded format. |
| "notBefore" | Date on which the certificate validity period begins in ISO format yyyy-mm-ddThh:nn:ssZ |
| "notAfter" | Date on which the certificate validity period ends in ISO format yyyy-mm-ddThh:nn:ssZ |
| "issuerName" | Distinguished name (DN) of entity who has signed and issued the certificate. |
| "subjectName" | Distinguished name (DN) of the subject. |
| "subjectPublicKeyAlgorithm" | Algorithm used in subject's public key, e.g. "dsa". |
| "subjectKeyIdentifier" | The subject key identifier extension, if present, in hex-encoded format. |
| "authorityKeyIdentifier" | The authority key identifier extension, if present, in hex-encoded format. |
| "rfc822Name" | Internet mail address contained in a subjectAltName extension, if present. |
| "isCA" | Returns "1" if the subject type is a CA, otherwise returns "0". |
| "keyUsageString" | keyUsage flags in text format, e.g. "digitalSignature,nonRepudiation". |
| "extKeyUsageString" | extKeyUsage purposes in text format, e.g. "codeSigning,timeStamping". |
| "cRLDistributionPointsURI" | First URI found in cRLDistributionPoints, if any. |
| "authorityInfoAccessURI" | First URI found in authorityInfoAccess, if any. |
| "subjectAltName" | Subject alternative name extension, if present. |
| "hashAlgorithm" | Hash algorithm used in signature, e.g. "sha256". |
| "pssParams" | Parameters used for RSA-PSS (if applicable). |
VB6/C equivalent: X509_QueryCert
Read an X.509 certificate into a base64 string from PKCS-7 "certs-only" data.
public static string ReadCertStringFromP7Chain( string inputFile, int index )
Public Shared Function ReadCertStringFromP7Chain ( _ inputFile As String, _ index As Integer _ ) As String
VB6/C equivalent: X509_ReadCertStringFromP7Chain
Read an X.509 certificate into a base64 string from PKCS-12 PFX/.p12 data.
public static string ReadCertStringFromPFX( string inputFile, string password )
Public Shared Function ReadCertStringFromPFX ( _ inputFile As String, _ password As String _ ) As String
VB6/C equivalent: X509_ReadCertStringFromPFX
Create a base64 string representation of a X.509 certificate file.
public static string ReadStringFromFile( string certFile )
Public Shared Function ReadStringFromFile ( _ certFile As String _ ) As String
VB6/C equivalent: X509_ReadStringFromFile
Create a new X.509 certificate file from a base64 string representation.
public static int SaveFileFromString( string newCertFile, string certString, bool inPEMFormat )
Public Shared Function SaveFileFromString ( _ newCertFile As String, _ certString As String, _ inPEMFormat As Boolean _ ) As Integer
A PEM format file will start with -----BEGIN CERTIFICATE-----.
VB6/C equivalent: X509_SaveFileFromString
Dump details of an X.509 certificate or a X.509 certificate revocation list (CRL) or a PKCS-10 certificate signing request (CSR) to a text file.
public static int TextDump( string outputFile, string certFile, X509.OutputOpts outOpts )
Public Shared Function TextDump ( _ outputFile As String, _ certFile As String, _ outOpts As X509.OutputOpts _ ) As Integer
VB6/C equivalent: X509_TextDump
Dump details of an X.509 certificate or a X.509 certificate revocation list (CRL) or a PKCS-10 certificate signing request (CSR) to a string.
public static string TextDumpToString( string certFile, X509.OutputOpts outOpts )
Public Shared Function TextDumpToString ( _ certFile As String, _ outOpts As X509.OutputOpts _ ) As String
VB6/C equivalent: X509_TextDumpToString
Validate a certificate path.
public static int ValidatePath( string certListOrP7File, string trustedCert, bool noTimeCheck )
Public Shared Function ValidatePath ( _ certListOrP7File As String, _ trustedCert As String, _ noTimeCheck As Boolean _ ) As Integer
VB6/C equivalent: X509_ValidatePath
Verify that an X.509 certificate has been signed by its issuer.
public static int VerifyCert( string certToVerify, string issuerCert )
Public Shared Function VerifyCert ( _ certToVerify As String, _ issuerCert As String _ ) As Integer
VB6/C equivalent: X509_VerifyCert
Generate bytes using an eXtendable-Output Function (XOF).
public static byte[] Bytes( int numBytes, byte[] message, Xof.Alg xofAlg )
Public Shared Function Bytes ( _ numBytes As Integer, _ message As Byte(), _ xofAlg As Xof.Alg _ ) As Byte()
VB6/C equivalent: XOF_Bytes
Authenticated encryption algorithm.
public enum AeadAlgorithm
Public Enumeration AeadAlgorithm
| Member name | Description | |
|---|---|---|
| Aes_128_Gcm | Use the AEAD_AES_128_GCM authenticated encryption algorithm from RFC 5116. | |
| Aes_192_Gcm | Use the AES-192-GCM authenticated encryption algorithm in the same manner as RFC 5116. | |
| Aes_256_Gcm | Use the AEAD_AES_256_GCM authenticated encryption algorithm from RFC 5116. | |
| ChaCha20_Poly1305 | Use the AEAD_CHACHA20_POLY1305 authenticated encryption algorithm from RFC 8439. |
Options for ASN.1 methods
[FlagsAttribute] public enum Options
<FlagsAttribute> _ Public Enumeration Options
| Member name | Description | |
|---|---|---|
| Default | Default options | |
| NoComments | Hide the comments [default=show comments] | |
| AddLevels | Show level numbers [default=hide level numbers] |
Block Cipher Algorithm
public enum CipherAlgorithm
Public Enumeration CipherAlgorithm
| Member name | Description | |
|---|---|---|
| Tdea | Triple DES (TDEA, 3DES, des-ede3) | |
| Aes128 | AES-128 | |
| Aes192 | AES-192 | |
| Aes256 | AES-256 |
Advanced options
[FlagsAttribute] public enum Opts
<FlagsAttribute> _ Public Enumeration Opts
| Member name | Description | |
|---|---|---|
| Default | Default options | |
| PrefixIV | Prefix (prepend) the IV before the ciphertext in the output (ignored for ECB mode) |
Advanced options for CMS compressed-data objects
[FlagsAttribute] public enum ComprDataOptions
<FlagsAttribute> _ Public Enumeration ComprDataOptions
| Member name | Description | |
|---|---|---|
| Default | Default options. | |
| NoInflate | Extract the compressed data as is without inflation. |
Content encryption algorithm.
public enum ContentEncrAlg
Public Enumeration ContentEncrAlg
| Member name | Description | |
|---|---|---|
| Default | Default = Triple DES CAUTION! | |
| Tdea | Triple DES (TDEA, 3DES, des-ede3) | |
| Aes128 | AES-128 | |
| Aes192 | AES-192 | |
| Aes256 | AES-256 | |
| Aes_128_Gcm | AES-128-GCM authenticated encryption algorithm from RFC5116. | |
| Aes_192_Gcm | AES-192-GCM authenticated encryption algorithm in the same manner as RFC5116. | |
| Aes_256_Gcm | AES-256-GCM authenticated encryption algorithm from RFC5116. | |
| ChaCha20_Poly1305 | AEAD_CHACHA20_POLY1305 authenticated encryption algorithm from RFC8439. |
Advanced options for CMS enveloped-data objects.
[FlagsAttribute] public enum EnvDataOptions
<FlagsAttribute> _ Public Enumeration EnvDataOptions
| Member name | Description | |
|---|---|---|
| None | Default options. | |
| FormatBase64 | Encode output in base64 (default = binary). | |
| AltAlgId | Use alternative (non-standard) alternative TeleTrusT Content Encryption Algorithm Identifier. | |
| BigFile | Use to speed up the encryption of large files (binary file to binary file only). | |
| Mgf1Sha1 | Force the MGF1 hash function to be SHA-1 (RSA-OAEP only, default = same as encoding hash function). | |
| Authenticated | Use AES-GCM authenticated encryption instead of AES-CBC (redundant as of [v22.0]). |
Output format.
public enum Format
Public Enumeration Format
| Member name | Description | |
|---|---|---|
| Default | Default output format | |
| Binary | Binary output (default) | |
| FormatBase64 | Output is encoded in base64 (default = binary). |
Key encryption algorithm for key transport (ktri) technique
public enum KeyEncrAlgorithm
Public Enumeration KeyEncrAlgorithm
| Member name | Description | |
|---|---|---|
| Default | Default | |
| Rsa_Pkcs1v1_5 | RSAES-PKCS-v1_5 (rsaEncryption) | |
| Rsa_Oaep | RSAES-OAEP |
Options for reading CMS objects.
[FlagsAttribute] public enum ReadOptions
<FlagsAttribute> _ Public Enumeration ReadOptions
| Member name | Description | |
|---|---|---|
| None | Default options. | |
| BigFile | Use to speed up the encryption of large files (binary file input only). |
Signature algorithm for CMS signed-data objects.
public enum SigAlg
Public Enumeration SigAlg
| Member name | Description | |
|---|---|---|
| Default | Use default signature algorithm (rsa-sha1/sha1WithRSAEncryption) | |
| Rsa_Sha1 | Use sha1WithRSAEncryption (rsa-sha1) signature algorithm [default] | |
| Rsa_Sha224 | Use sha224WithRSAEncryption (rsa-sha224) signature algorithm | |
| Rsa_Sha256 | Use sha256WithRSAEncryption (rsa-sha256) signature algorithm | |
| Rsa_Sha384 | Use sha384WithRSAEncryption (rsa-sha384) signature algorithm | |
| Rsa_Sha512 | Use sha512WithRSAEncryption (rsa-sha512) signature algorithm | |
| Rsa_Md5 | Use md5WithRSAEncryption (rsa-md5) signature algorithm [legacy, not recommended] | |
| Rsa_Pss_Sha1 | Use RSA-PSS signature algorithm with SHA-1 | |
| Rsa_Pss_Sha224 | Use RSA-PSS signature algorithm with SHA-224 | |
| Rsa_Pss_Sha256 | Use RSA-PSS signature algorithm with SHA-256 | |
| Rsa_Pss_Sha384 | Use RSA-PSS signature algorithm with SHA-384 | |
| Rsa_Pss_Sha512 | Use RSA-PSS signature algorithm with SHA-512 | |
| Ecdsa_Sha1 | Use ecdsaWithSHA1 (ecdsa-sha1) signature algorithm | |
| Ecdsa_Sha224 | Use ecdsaWithSHA224 (ecdsa-sha224) signature algorithm | |
| Ecdsa_Sha256 | Use ecdsaWithSHA256 (ecdsa-sha256) signature algorithm | |
| Ecdsa_Sha384 | Use ecdsaWithSHA384 (ecdsa-sha384) signature algorithm | |
| Ecdsa_Sha512 | Use ecdsaWithSHA512 (ecdsa-sha512) signature algorithm | |
| Ed25519 | Use Ed25519 signature algorithm [RFC8032] | |
| Ed448 | Use Ed448 signature algorithm [RFC8032 |
Advanced options for CMS signed-data objects
[FlagsAttribute] public enum SigDataOptions
<FlagsAttribute> _ Public Enumeration SigDataOptions
| Member name | Description | |
|---|---|---|
| Default | Default option | |
| ExcludeCerts | Exclude X.509 certs from output. | |
| ExcludeData | Exclude data from output. | |
| CertsOnly | Create a "certs-only" PKCS#7 certficate chain. | |
| IncludeAttributes | To add signed attributes (default = no signed attributes) including content-type and message-digest plus any more added below. | |
| AddSignTime | Add signing time to the signed attributes (requires IncludeAttributes). | |
| AddSmimeCapabilities | Add S/MIME capabilities to the signed attributes (requires IncludeAttributes). | |
| AddSigningCertificate | Add an ESS Signing Certificate attribute to the signed attributes (requires IncludeAttributes). | |
| AddAlgProtection | Add an Algorithm Protection Attribute [RFC6211] to the signed attributes (requires IncludeAttributes). | |
| FormatBase64 | Create output/expect input in base64 format (default = binary). | |
| NoOuter | Create a "naked" SignedData object with no outerContentInfo as permitted by PKCS#7 v1.6 (specialist option). | |
| AltAlgId | Use alternative (non-standard) signature algorithm identifiers, e.g. 'sha1withRSAEncryption' instead of 'rsaEncryption'. | |
| BigFile | Use to speed up the processing of large files. | |
| Mgf1Sha1 | Force the MGF1 hash function to be SHA-1 (RSASSA-PSS only, default = same as encoding hash function). | |
| Pss_SaltLenZero | Use a zero-length salt in an RSA-PSS signature (default = hLen the length of the digest output). | |
| PseudoSig | Create/sign a "pseudo" SignedData object with dummy placeholder signature. |
Conversion directions for ByteEncoding.
public enum EncodingConversion
Public Enumeration EncodingConversion
| Member name | Description | |
|---|---|---|
| Utf8_From_Latin1 | Converts UTF-8-encoded bytes into Latin-1-encoded | |
| Latin1_From_Utf8 | Converts Latin-1-encoded bytes into UTF-8-encoded |
Byte order.
public enum EndianNess
Public Enumeration EndianNess
| Member name | Description | |
|---|---|---|
| BigEndian | Most-significant byte first | |
| LittleEndian | Least-significant byte first |
Supported curve names.
public enum CurveName
Public Enumeration CurveName
| Member name | Description | |
|---|---|---|
| Secp192r1 | NIST curve P-192 | |
| Secp224r1 | NIST curve P-224 | |
| Secp256r1 | NIST curve P-256 | |
| Secp384r1 | NIST curve P-384 | |
| Secp521r1 | NIST curve P-521 | |
| Secp256k1 | "Bitcoin" curve | |
| P_192 | NIST curve P-192 (synonym for secp192r1) | |
| P_224 | NIST curve P-256 (synonym for secp256r1) | |
| P_256 | NIST curve P-224 (synonym for secp224r1) | |
| P_384 | NIST curve P-384 (synonym for secp384r1) | |
| P_521 | NIST curve P-521 (synonym for secp521r1) | |
| Prime192v1 | Alternative name for NIST curve P-192 | |
| Prime256v1 | Alternative name for NIST curve P-256 | |
| BrainpoolP256r1 | ECC Brainpool curve [RFC5639] | |
| BrainpoolP384r1 | ECC Brainpool curve [RFC5639] | |
| BrainpoolP512r1 | ECC Brainpool curve [RFC5639] | |
| Ed25519 | Safe curve for EdDSA | |
| Ed448 | Safe curve for EdDSA | |
| X25519 | Safe curve for ECDH | |
| X448 | Safe curve for ECDH |
Format for output files.
public enum Format
Public Enumeration Format
| Member name | Description | |
|---|---|---|
| Default | Default = binary | |
| Binary | Binary DER-encoded | |
| PEM | PEM-encoded text file |
Key type for unencrypted key file.
public enum KeyType
Public Enumeration KeyType
| Member name | Description | |
|---|---|---|
| Default | Save key in the default format. | |
| Pkcs8PrivateKeyInfo | Save a NIST/SEC curve private key in PKCS#8 PrivateKeyInfo format (ignored for a public key) | |
| Legacy | Save a safe private key in "legacy" PKCS#8 v1 format (default is v2 OneAsymmetricKey) | |
| PrivateKey | Key value represents a private key (use for reading safe curves) | |
| PublicKey | Key value represents a public key (use for reading safe curves) |
Password-based encryption scheme to encrypt the private key file.
public enum PbeScheme
Public Enumeration PbeScheme
| Member name | Description | |
|---|---|---|
| Default | Default option (pbeWithSHAAnd3-KeyTripleDES-CBC) | |
| PbeWithSHAAnd_KeyTripleDES_CBC | pbeWithSHAAnd3-KeyTripleDES-CBC from PKCS#12 | |
| Pbe_Pbkdf2_des_EDE3_CBC | "pkcs5PBES2" with key derivation function "pkcs5PBKDF2" and encryption scheme "des-EDE3-CBC" | |
| Pbe_Pbkdf2_aes128_CBC | "pkcs5PBES2" with key derivation function "pkcs5PBKDF2" and encryption scheme "aes128-CBC" | |
| Pbe_Pbkdf2_aes192_CBC | "pkcs5PBES2" with key derivation function "pkcs5PBKDF2" and encryption scheme "aes192-CBC" | |
| Pbe_Pbkdf2_aes256_CBC | "pkcs5PBES2" with key derivation function "pkcs5PBKDF2" and encryption scheme "aes256-CBC" |
Base for encoding methods
public enum EncodingBase
Public Enumeration EncodingBase
| Member name | Description | |
|---|---|---|
| Base64 | Base64 encoding | |
| Base16 | Base16 encoding (i.e. hexadecimal) |
Message Digest Hash Algorithm
public enum HashAlgorithm
Public Enumeration HashAlgorithm
| Member name | Description | |
|---|---|---|
| Sha1 | SHA-1 (as per FIPS PUB 180-4) | |
| Md5 | MD5 (as per RFC 1321) [legacy, not recommended] | |
| Md2 | MD2 (as per RFC 1319) [legacy, definitely not recommended] | |
| Sha224 | SHA-224 (as per FIPS PUB 180-4) | |
| Sha256 | SHA-256 (as per FIPS PUB 180-4) | |
| Sha384 | SHA-384 (as per FIPS PUB 180-4) | |
| Sha512 | SHA-512 (as per FIPS PUB 180-4) | |
| Sha3_224 | SHA-3-224 (as per FIPS PUB 202) | |
| Sha3_256 | SHA-3-256 (as per FIPS PUB 202) | |
| Sha3_384 | SHA-3-384 (as per FIPS PUB 202) | |
| Sha3_512 | SHA-3-256 (as per FIPS PUB 202) | |
| Ripemd160 | RIPEMD-160 | |
| Bitcoin160 | RIPEMD-160 hash of a SHA-256 hash (RIPEMD160(SHA256(m))) |
AEAD functions supported for HPKE
public enum AeadAlg
Public Enumeration AeadAlg
| Member name | Description | |
|---|---|---|
| None | No AEAD algorithm. | |
| Aes_128_Gcm | Use the AEAD_AES_128_GCM authenticated encryption algorithm from RFC5116. | |
| Aes_256_Gcm | Use the AEAD_AES_256_GCM authenticated encryption algorithm from RFC5116. | |
| ChaCha20_Poly1305 | Use the AEAD_CHACHA20_POLY1305 authenticated encryption algorithm from RFC8439. |
Supported ECDH curves for HPKE
public enum CurveName
Public Enumeration CurveName
| Member name | Description | |
|---|---|---|
| P_256 | NIST curve P-256 | |
| P_384 | NIST curve P-384 | |
| P_521 | NIST curve P-521 | |
| X25519 | ECDH curve X25519 from RFC7748 | |
| X448 | ECDH curve X448 from RFC7748 |
Options to format or re-encode output.
public enum OutputOpts
Public Enumeration OutputOpts
| Member name | Description | |
|---|---|---|
| Default | Default = output as ephemeral "internal" key string. | |
| KeyAsHex | Output key in hex format compatible with test vectors in [RFC9180] |
Hash algorithms for KDF
public enum HashAlg
Public Enumeration HashAlg
| Member name | Description | |
|---|---|---|
| Sha1 | SHA-1 (as per FIPS PUB 180-4) | |
| Sha224 | SHA-224 (as per FIPS PUB 180-4) | |
| Sha256 | SHA-256 (as per FIPS PUB 180-4) | |
| Sha384 | SHA-384 (as per FIPS PUB 180-4) | |
| Sha512 | SHA-512 (as per FIPS PUB 180-4) |
Key derivation functions
public enum KdfAlg
Public Enumeration KdfAlg
| Member name | Description | |
|---|---|---|
| X963 | ANSI-X9.63-KDF key derivation function (default) | |
| Hkdf | HMAC-based Key Derivation Function (HKDF) from [RFC5869] |
Key wrap algorithms for KDF
public enum KeyWrapAlg
Public Enumeration KeyWrapAlg
| Member name | Description | |
|---|---|---|
| Default | Default for Cms.MakeEnvData only. | |
| Cms3DESwrap | Triple-DES Key Wrap algorithm from [RFC3217] | |
| Aes128_wrap | AES-128 key wrap from [RFC3394] | |
| Aes192_wrap | AES-192 key wrap from [RFC3394] | |
| Aes256_wrap | AES-256 key wrap from [RFC3394] |
Cipher Mode
public enum Mode
Public Enumeration Mode
| Member name | Description | |
|---|---|---|
| ECB | Electronic Code Book mode | |
| CBC | Cipher Block Chaining mode | |
| OFB | Output Feedback mode | |
| CFB | Cipher Feedback mode | |
| CTR | Counter mode | |
| GCM | Galois/Counter mode (AES only) |
Block Cipher Padding
public enum Padding
Public Enumeration Padding
| Member name | Description | |
|---|---|---|
| Default | Use default padding | |
| NoPad | No padding is added | |
| Pkcs5 | The padding scheme described in PKCS#5/#7 | |
| OneAndZeroes | Pad with 0x80 followed by as many zero bytes necessary to fill the block | |
| AnsiX923 | The padding scheme described in ANSI X9.23 | |
| W3CPadding | The padding scheme described in W3C https://www.w3.org/TR/xmlenc-core1/#sec-Padding |
Specialist options.
[FlagsAttribute] public enum Options
<FlagsAttribute> _ Public Enumeration Options
| Member name | Description | |
|---|---|---|
| Default | Default options: re-encrypt private key with "TripleDES-SHA1", encrypt certificate with 40-bit RC2, output in DER binary form. | |
| PlainCert | Store the certificate in unencrypted form (default is encrypted with 40-bit RC2). | |
| StrongCert | Encrypt the certificate with "stronger" TripleDES-SHA1 (default is "weak" 40-bit RC2). | |
| CloneKey | Store the private key in the exact form of the pkcs-8 input file (default is to re-encrypt with Triple DES). | |
| Aes256_Sha256 | Override other encryption options and encrypt both the private key and certificate using "AES256-SHA256" | |
| DoubleEncrypt | Double-encrypt the private key (specialist option). | |
| AltFormat | Create a PFX file with the exact peculiarities used by Microsoft (default is OpenSSL). | |
| FormatPem | Create the output file in PEM format (default is DER-encoded binary). |
Pseudorandom function (PRF) algorithm.
public enum Alg
Public Enumeration Alg
| Member name | Description | |
|---|---|---|
| Kmac128 | KMAC128 as per NIST SP 800-185 | |
| Kmac256 | KMAC256 as per NIST SP 800-185 |
Rng options
public enum Options
Public Enumeration Options
| Member name | Description | |
|---|---|---|
| Default | Default option | |
| NoIntelDrng | Turn off support for INTEL(R) DRNG for the current session. |
Required security strength for user-prompted entropy
public enum Strength
Public Enumeration Strength
| Member name | Description | |
|---|---|---|
| Default | Default option | |
| Bits_112 | 112 bits of security (default) | |
| Bits_128 | 128 bits of security | |
| Bits_192 | 192 bits of security | |
| Bits_256 | 256 bits of security |
Advanced options.
[FlagsAttribute] public enum AdvOptions
<FlagsAttribute> _ Public Enumeration AdvOptions
| Member name | Description | |
|---|---|---|
| Default | Default options. | |
| Mgf1_Sha1 | Force the MGF hash function to be SHA-1 (OAEP only, default = same as encoding set by Rsa.HashAlg) |
Encoding method for encryption.
public enum EME
Public Enumeration EME
| Member name | Description | |
|---|---|---|
| PKCSv1_5 | EME-PKCS1-v1_5 encoding method | |
| OAEP | EME-OAEP encoding method |
Format for saved RSA key.
public enum Format
Public Enumeration Format
| Member name | Description | |
|---|---|---|
| Default | Default = Binary | |
| Binary | Binary DER-encoded | |
| PEM | PEM Format | |
| SSL | PEM format compatible with OpenSSL |
Hash function for OAEP encoding.
public enum HashAlg
Public Enumeration HashAlg
| Member name | Description | |
|---|---|---|
| Sha1 | SHA-1 (default) | |
| Sha224 | SHA-224 | |
| Sha256 | SHA-256 | |
| Sha384 | SHA-384 | |
| Sha512 | SHA-512 |
Password-based encryption scheme to be used to encrypt the private key file.
public enum PbeOptions
Public Enumeration PbeOptions
| Member name | Description | |
|---|---|---|
| Default | Default option (pbeWithSHAAnd3-KeyTripleDES-CBC) | |
| PbeWithSHAAnd_KeyTripleDES_CBC | pbeWithSHAAnd3-KeyTripleDES-CBC from PKCS#12 | |
| Pbe_Pbkdf2_des_EDE3_CBC | "pkcs5PBES2" with key derivation function "pkcs5PBKDF2" and encryption scheme "des-EDE3-CBC" | |
| Pbe_Pbkdf2_aes128_CBC | "pkcs5PBES2" with key derivation function "pkcs5PBKDF2" and encryption scheme "aes128-CBC" | |
| Pbe_Pbkdf2_aes192_CBC | "pkcs5PBES2" with key derivation function "pkcs5PBKDF2" and encryption scheme "aes192-CBC" | |
| Pbe_Pbkdf2_aes256_CBC | "pkcs5PBES2" with key derivation function "pkcs5PBKDF2" and encryption scheme "aes256-CBC" | |
| PbeWithMD5AndDES_CBC | pbeWithMD5AndDES-CBC [legacy, not recommended for new implementations] | |
| PbeWithMD2AndDES_CBC | pbeWithMD2AndDES-CBC [legacy, not recommended for new implementations] | |
| PbeWithSHA1AndDES_CBC | pbeWithSHA1AndDES-CBC [legacy, not recommended for new implementations] | |
| Pkcs5PBES2_des_EDE3_CBC | "pkcs5PBES2" with "pkcs5PBKDF2" and "des-EDE3-CBC" [Synonym retained for backwards compatibility] |
Choices for public exponent (e)
public enum PublicExponent
Public Enumeration PublicExponent
| Member name | Description | |
|---|---|---|
| Exp_EQ_3 | Set exponent equal to 3 (F0) | |
| Exp_EQ_5 | Set exponent equal to 5 (F1) | |
| Exp_EQ_17 | Set exponent equal to 17 (F2) | |
| Exp_EQ_257 | Set exponent equal to 257 (F3) | |
| Exp_EQ_65537 | Set exponent equal to 65537 (F4) |
Options when converting between internal RSA key and XML.
[FlagsAttribute] public enum XmlOptions
<FlagsAttribute> _ Public Enumeration XmlOptions
| Member name | Description | |
|---|---|---|
| ExcludePrivateParams | Exclude private key parameters | |
| ForceRSAKeyValue | Create XML in .NET-compatible RSAKeyValue format (ToXML only) | |
| HexBinaryFormat | Create XML in non-standard hex format (ToXML only) | |
| RequirePrivate | Require private key to exist in the XML input or fail (FromXML only) |
Signature algorithm
public enum SigAlgorithm
Public Enumeration SigAlgorithm
| Member name | Description | |
|---|---|---|
| Default | Use default signature algorithm [rsa-sha1/sha1WithRSAEncryption] | |
| Rsa_Sha1 | Use sha1WithRSAEncryption (rsa-sha1) signature algorithm [default] | |
| Rsa_Sha224 | Use sha224WithRSAEncryption (rsa-sha224) signature algorithm | |
| Rsa_Sha256 | Use sha256WithRSAEncryption (rsa-sha256) signature algorithm | |
| Rsa_Sha384 | Use sha384WithRSAEncryption (rsa-sha384) signature algorithm | |
| Rsa_Sha512 | Use sha512WithRSAEncryption (rsa-sha512) signature algorithm | |
| Rsa_Md5 | Use md5WithRSAEncryption (rsa-md5) signature algorithm [legacy, not recommended] | |
| Rsa_Pss_Sha1 | Use RSA-PSS signature algorithm with SHA-1 | |
| Rsa_Pss_Sha224 | Use RSA-PSS signature algorithm with SHA-224 | |
| Rsa_Pss_Sha256 | Use RSA-PSS signature algorithm with SHA-256 | |
| Rsa_Pss_Sha384 | Use RSA-PSS signature algorithm with SHA-384 | |
| Rsa_Pss_Sha512 | Use RSA-PSS signature algorithm with SHA-512 | |
| Ecdsa_Sha1 | Use ecdsaWithSHA1 (ecdsa-sha1) signature algorithm | |
| Ecdsa_Sha224 | Use ecdsaWithSHA224 (ecdsa-sha224) signature algorithm | |
| Ecdsa_Sha256 | Use ecdsaWithSHA256 (ecdsa-sha256) signature algorithm | |
| Ecdsa_Sha384 | Use ecdsaWithSHA384 (ecdsa-sha384) signature algorithm | |
| Ecdsa_Sha512 | Use ecdsaWithSHA512 (ecdsa-sha512) signature algorithm | |
| Ed25519 | Use Ed25519 signature algorithm | |
| Ed448 | Use Ed448 signature algorithm |
Encodings for signature output.
public enum Encoding
Public Enumeration Encoding
| Member name | Description | |
|---|---|---|
| Default | Default encoding (base64) | |
| Base64 | Base64 encoding (default) | |
| Base64url | URL-safe base64 encoding as in section 5 of [RFC4648] | |
| Base16 | Base16 encoding (i.e. hexadecimal) |
Specialist options for signatures.
[FlagsAttribute] public enum SigOptions
<FlagsAttribute> _ Public Enumeration SigOptions
| Member name | Description | |
|---|---|---|
| Default | Use default options for signature. | |
| UseDeterministic | ECDSA only: Use the deterministic digital signature generation procedure of [RFC6979] for ECDSA signature [default=random k]. | |
| Asn1DERStructure | ECDSA only: Form ECDSA signature value as a DER-encoded ASN.1 structure [default=r||s]. | |
| PssSaltLenHlen | RSA-PSS only: Set the salt length to hLen, the length of the output of the hash function [default]. | |
| PssSaltLenMax | RSA-PSS only: Set the salt length to the maximum possible (like OpenSSL). | |
| PssSaltLen20 | RSA-PSS only: Set the salt length to be exactly 20 bytes regardless of the hash algorithm. | |
| PssSaltLenZero | RSA-PSS only: Set the salt length to be zero. | |
| Mgf1Sha1 | RSA-PSS only: Force the MGF hash function to be SHA-1 [default = same as signature hash algorithm] |
Specialist options for verifying a signature.
[FlagsAttribute] public enum VerifyOpts
<FlagsAttribute> _ Public Enumeration VerifyOpts
| Member name | Description | |
|---|---|---|
| Default | Use default options. | |
| Mgf1Sha1 | RSA-PSS only: Force the MGF hash function to be SHA-1 [default = same as signature hash algorithm] |
Options for S/MIME methods
[FlagsAttribute] public enum Options
<FlagsAttribute> _ Public Enumeration Options
| Member name | Description | |
|---|---|---|
| Default | Default options | |
| EncodeBase64 | Encode output in base64 | |
| EncodeBinary | Encode body in binary encoding | |
| AddX | Add an "x-" to the content subtype (for compatibility with legacy applications) |
Wipe options.
public enum Options
Public Enumeration Options
| Member name | Description | |
|---|---|---|
| Default | Default options (DOD 7-pass) | |
| Dod7Pass | DOD 7-pass (default) | |
| Simple | Overwrite with single pass of zero bytes (quicker but less secure). |
Options to create X.509 certificate.
[FlagsAttribute] public enum CertOptions
<FlagsAttribute> _ Public Enumeration CertOptions
| Member name | Description | |
|---|---|---|
| Default | Default options | |
| FormatPem | Create in PEM-encoded text file [default = binary DER-encoded] | |
| UTF8String | Encode distinguished name as UTF8String [default = PrintableString] | |
| NoBasicConstraints | Disable the BasicConstraints extension [default = include] | |
| SetAsCA | Set the BasicConstraints subject type to be a CA [default = End Entity] | |
| VersionOne | Create a Version 1 certificate, i.e. no extensions [default = Version 3] | |
| AuthKeyId | Add the issuer's KeyIdentifier, if present, as an AuthorityKeyIdentifer [default = do not add] | |
| Pss_SaltLenZero | Use a zero-length salt in an RSA-PSS signature [default = hLen the length of the digest output] | |
| Ecdsa_Deterministic | Use the deterministic digital signature generation procedure of [RFC6979] for an ECDSA signature. |
Options to create Certificate Revocation List (CRL)
[FlagsAttribute] public enum CrlOptions
<FlagsAttribute> _ Public Enumeration CrlOptions
| Member name | Description | |
|---|---|---|
| Default | Default options | |
| FormatPem | Create in PEM-encoded text file [default = binary DER-encoded] | |
| Pss_SaltLenZero | Use a zero-length salt in an RSA-PSS signature [default = hLen the length of the digest output] | |
| Ecdsa_Deterministic | Use the deterministic digital signature generation procedure of [RFC6979] for an ECDSA signature. |
Options to create PKCS#10 certificate signing request (CSR)
[FlagsAttribute] public enum CsrOptions
<FlagsAttribute> _ Public Enumeration CsrOptions
| Member name | Description | |
|---|---|---|
| Default | Default options | |
| FormatBinary | Create in binary format [default = PEM-encoded text file] | |
| UTF8String | Encode distinguished name as UTF8String [default = PrintableString] | |
| RequestKludge | Create a request with the "kludge" that omits the strictly mandatory attributes completely [default = include attributes with zero-length field] | |
| Pss_SaltLenZero | Use a zero-length salt in an RSA-PSS signature [default = hLen the length of the digest output] | |
| Ecdsa_Deterministic | Use the deterministic digital signature generation procedure of [RFC6979] for an ECDSA signature. |
Options for key usage in certificate
[FlagsAttribute] public enum KeyUsageOptions
<FlagsAttribute> _ Public Enumeration KeyUsageOptions
| Member name | Description | |
|---|---|---|
| None | Key usage extension is not included. | |
| DigitalSignature | subject public key is used for verifying digital signatures. | |
| NonRepudiation | subject public key is used to verify digital signatures used to provide a non-repudiation service. | |
| KeyEncipherment | subject public key is used for enciphering private or secret keys, i.e., for key transport. | |
| DataEncipherment | subject public key is used for directly enciphering raw user data (uncommon). | |
| KeyAgreement | subject public key is used for key agreement. | |
| KeyCertSign | subject public key is used for verifying signatures on public key certificates. | |
| CrlSign | subject public key is used for verifying signatures on certificate revocation lists. | |
| EncipherOnly | subject public key may be used only for enciphering data while performing key agreement (only if keyAgreement bit is also set). | |
| DecipherOnly | subject public key may be used only for deciphering data while performing key agreement (only if keyAgreement bit is also set). |
Options to format or re-encode output.
[FlagsAttribute] public enum OutputOpts
<FlagsAttribute> _ Public Enumeration OutputOpts
| Member name | Description | |
|---|---|---|
| Default | Default options | |
| Latin1 | Encode distinguished name in Latin-1 encoding, if possible. | |
| Unicode | Output distinguished name in Unicode character set (UTF-8 or UTF-16 as appropriate). | |
| Ldap | Output distinguished name in LDAP string representation. | |
| Decimal | Output serial number in decimal format [default = hex]. |
eXtendable-Output Function (XOF) algorithm.
public enum Alg
Public Enumeration Alg
| Member name | Description | |
|---|---|---|
| Shake128 | SHAKE128 (as per FIPS PUB 202) | |
| Shake256 | SHAKE256 (as per FIPS PUB 202) | |
| Mgf1_Sha1 | MGF1-SHA-1 (as per PKCS#1) | |
| Mgf1_Sha256 | MGF1-SHA-256 (as per PKCS#1) | |
| Mgf1_Sha512 | MGF1-SHA-512 (as per PKCS#1) |
0 = OK, success, no error (SUCCESS_NO_ERROR) 1 = Cannot open input file (OPEN_ERROR) 2 = Cannot create output file (CREATE_ERROR) 3 = File read error (READ_ERROR) 4 = File write error (WRITE_ERROR) 5 = Not enough memory (MEMORY_ERROR) 6 = Parameter is wrong or missing (BAD_PARAM_ERROR) 7 = Data in wrong format (BAD_FORMAT_ERROR) 8 = Invalid data (INVALID_DATA_ERROR) 9 = Unexpected end of file found (EOF_ERROR) 10 = Required data not found (MISSING_ERROR) 11 = Value out of range (OUT_OF_RANGE_ERROR) 12 = Duplicate data (DUP_ERROR) 13 = Misc file IO error (IO_ERROR) 14 = Unexpected NULL value (NULL_ERROR) 15 = Decryption error (DECRYPT_ERROR) 16 = Item has expired or is not yet valid (EXPIRED_ERROR) 17 = Invalid option (BAD_FLAG_ERROR) 18 = Failed to wipe data (WIPE_ERROR) 19 = Item is not supported (NOT_SUPPORTED_ERROR) 20 = No data found to process (NO_DATA_ERROR) 21 = No match found (NO_MATCH_ERROR) 22 = Signature is invalid (SIGNATURE_ERROR) 23 = Failed a test e.g. known answer test (TEST_FAILED_ERROR) 24 = Key generation failed (KEYGEN_FAILED_ERROR) 25 = Certificate issuer error (ISSUER_ERROR) 26 = Data not a valid length (BAD_LENGTH_ERROR) 27 = Invalid XML format (BAD_XML_ERROR) 29 = Not a valid query (BAD_QUERY_ERROR) 30 = Not enough room in output buffer (SHORT_BUF_ERROR) 31 = Zlib compression error (ZLIB_COMPR_ERROR) 33 = Invalid key length (BAD_KEY_LEN_ERROR) 34 = Invalid block length (BAD_BLK_LEN_ERROR) 35 = Invalid mode (BAD_MODE_ERROR) 36 = Invalid key (BAD_KEY_ERROR) 37 = Invalid initialization vector (BAD_IV_ERROR) 38 = Invalid IV length (BAD_IV_LEN_ERROR) 39 = Unable to encode (ENCODING_ERROR) 42 = Item has been revoked (REVOCATION_ERROR) 43 = Certificate path is invalid (CERT_PATH_ERROR) 201 = PRNG: Cannot open input file (PRNG_ERR_FILE_OPEN) 202 = PRNG: Cannot create output file (PRNG_ERR_FILE_CREATE) 203 = PRNG: File read error (PRNG_ERR_FILE_READ) 204 = PRNG: File write error (PRNG_ERR_FILE_WRITE) 205 = PRNG: File locking error (PRNG_ERR_FILE_LOCK) 210 = PRNG: Uninstantiation failed (PRNG_ERR_UNINST) 211 = PRNG: Requested length is too large (PRNG_ERR_TOOBIG) 212 = PRNG: Function failed (PRNG_ERR_FAILURE) 213 = PRNG: Invalid input parameter (PRNG_ERR_BADPARAM) 214 = PRNG: Function is not available (PRNG_ERR_NOTAVAIL) 299 = PRNG: Catastrophic failure (PRNG_ERR_CATASTROPHIC) 9745 = Something not expected to happen has happened (INTERNAL_ERROR) 9999 = Miscellaneous error (MISC_ERROR)
If an error occurs the function will return one of the above nonzero error codes to indicate the general nature of the problem. This may be a positive or negative value depending on the function. Functions that normally return a positive value to indicate success will return an error code as a negative number. Functions that return zero to indicate success will return a nonzero error code, either positive or negative, depending on obscure historical reasons (to maintain backwards compatibility, sorry).
Use the PKI_ErrorLookup function
or the General.ErrorLookup method
to get the corresponding
error message for a given error code.
If you need to check for a specific error, please use the defined constants (XXXX_ERROR) instead of hard-coding the numerical values,
which may change in future releases.
More than one error may occur during a call to a function.
The code returned by a function will reflect the last error that occurred in the chain.
Use the PKI_ErrorCode function
or General.ErrorCode method
to find the code of the first error that occurred.
More details on the error can usually be found by using the
PKI_LastError
function or General.LastError method
which contains a description of the error or errors that have occurred.
Be warned that not all errors set this description.
The source code used in CryptoSys PKI Pro is original code written by David Ireland except for the following:
DUMPASN1.C program
by Peter Gutmann <http://www.cs.auckland.ac.nz/~pgut001/dumpasn1.c>.
BIGDIGITS
library first published June 2001 by David Ireland
<https://www.di-mgt.com.au/bigdigits.html>.
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the ``RSA Data Security, Inc. MD5 Message-Digest Algorithm'' in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as ``derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm'' in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided ``as is'' without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software.
Thanks to the guys at NullSoft for their Nullsoft Scriptable Install System.
[New in v20.5] We are most grateful to Daniel Gillmor for the latest S/MIME Example Keys and Certificates in RFC9216 [SMIME-LAMPS].
These are the primary references we used to create CryptoSys PKI Pro.
Other works we referred to in creating CryptoSys PKI Pro.
September 2025: Minor updates for markdown version. Updated links.
24 September 2024: Updated for Version 23.0. Added support for RSA-KEM with the Cryptographic Message Syntax (CMS).
Added new features and improvements for CMS enveloped-data and signed-data creation.
1 January 2024: Updated for Version 22.1. Upgraded random number generator (RNG) functions. Added support for Intel(R) DRNG, if available.
23 October 2023: Updated for Version 22.0. Added support for elliptic curves Ed448 and X448, ChaCha20Poly1305 authenticated encryption, the SCRYPT password-based key derivation function,
and Hybrid Public Key Encryption (HPKE) as per RFC9180.
1 January 2023: Updated for Version 21.0. Added support for SHA-3 and related functions.
10 September 2022: Updated for Version 20.6. Added support for CMS Authenticated-Enveloped-Data objects, and kekri and pwri recipientInfo types.
18 July 2022: Updated for Version 20.5. Added support for ECDH key agreement in enveloped-data objects and associated key derivation functions (KDF);
and support for AES256-SHA256 encryption in PKCS#12 (PFX) files.
24 April 2022: Updated for Version 20.4. Added support for ECC Brainpool curves.
1 January 2022: Updated for Version 20.3. Added interface to C++ (STL).
3 October 2021: Updated for Version 20.2. Consolidated VBA modules for 32/64-bits and VBA wrapper functions.
Rationalised .NET methods using .NET 4.0 optional parameters instead of .NET 2.0 overloads
13 March 2021: Updated for Version 20.1.
25 January 2021: Updated with documentation for VBA wrapper functions.
17 October 2020: Updated for Version 20.0.
12 May 2020: Updated for Version 12.4. Added additional security attributes for signed-data CMS objects.
6 March 2020: Updated for Version 12.3. Added support to generate GUID strings; added advanced options when creating X.509 certificates and PKCS#10 certificate requests;
and support for stronger encryption for certificates in PKCS#12 (PFX) files.
12 July 2019: Updated for Version 12.2.30. A minor upgrade to fix issues with multithreading and running on XP.
20 May 2019: Updated for Version 12.2.20. A minor upgrade to fix multithreading issues.
24 March 2019: Updated for Version 12.2. Improved support for CMS (PKCS#7) signed-data and enveloped-data objects, and RSA keys represented in JSON Web Key (JWK) format.
17 November 2018: Updated for Version 12.1. Added support for AES-GCM.
19 June 2018: Updated for Version 12.0. Added support for RSA-PSS and RSA-OAEP; and support for ECDSA in X.509 certificates; and ZLIB compression.
28 April 2018: Updated for Version 11.3. Beta release for v12.
8 August 2017: Updated for Version 11.2. Various minor fixes and new convenience functions.
20 May 2016: Updated for Version 11.1. Added new block cipher functions.
8 March 2016: Updated for Version 11.0. Added elliptic curve cryptography.
27 March 2015: Updated for Version 10.0. Major update to CryptoSys PKI Pro.
2 September 2014: Updated for Version 3.10. Added block cipher functions with padding and password-based encryption (PBE) functions.
8 September 2012: Updated for Version 3.9
14 January 2012: Updated for Version 3.8
1 July 2011: Updated for Version 3.7
25 August 2010: Updated for Version 3.6
2 May 2010: Updated for Version 3.5
19 December 2009: Updated for Version 3.4.
19 February 2009: Updated for Version 3.3.
2 February 2008: Updated for Version 3.2. Added new block cipher functions and RSA-KEM (since withdrawn).
2 August 2007: Updated for Version 3.1.
27 March 2007: Updated for Version 3.0. Changes to RNG and internal key string storage. Added HMAC functions.
12 August 2006: Updated for Version 2.9. Major re-write of manual.
26 April 2006: Updated for Version 2.8. Added section on signed-data objects.
11 December 2005: Updated for Version 2.7. Added VB.NET and C# syntax prototypes, and index.
20 August 2005: Updated for Version 2.6. Added extra RSA functions for XML and message encoding, and support for PEM key files.
Added section on Raw RSA Techniques. Added C/C++ syntax prototypes.
9 May 2005: Updated for Version 2.5. Added extra HASH and TDEA functions; rephrased action if self-test fails.
5 April 2005: Updated for Version 2.4. Added PFX functions and PEM export options.
1 March 2005: Updated for Version 2.3.
1 January 2005: Updated for Version 2.2. Added Boolean type description; added [in],[out] to parameters; other minor corrections.
29 November 2004: Minor corrections to manual.
24 November 2004: Updated for Version 2.1
September 2004: Minor amendments to manual.
25 February 2004: Version 2.0 manual first published by DI Management Services Pty Limited.
December 2002: Proposed PKI functions first posted on <https://cryptosys.net/pki.html>.