CryptoSys PKI Pro Manual

CIPHER_DecryptBytes

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.

VBA/VB6 Syntax

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)

C/C++ Syntax

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);

Parameters

lpOutput
[out] array of sufficient length to receive the output (must be at least as long as the input, see ** in remarks)).
nOutBytes
[in] specifying the length of the output buffer in bytes.
lpInput
[in] array containing the input data.
nInputLen
[in] specifying the length of the input data in bytes.
lpKey
[in] array containing the key.
nKeyLen
[in] the length of the key in bytes.
lpIV
[in] containing the initialization vector (IV), or zero (0) or NULL for ECB mode.
nIvLen
[in] the length of the IV in bytes.
szAlgModePad
[in] containing the block cipher algorithm, mode and padding (see Specifying the algorithm, mode and padding for generic block cipher functions).
nOptions
[in] option flags:
Zero (0) for default options. Optionally add:
PKI_IV_PREFIX to expect the IV to be prepended before the ciphertext in the input (ignored for ECB mode).

Returns (VBA/C)

If successful, the return value is the number of bytes in or required in the output; otherwise it returns a negative error code.

VBA Wrapper Syntax

Public Function cipherDecryptBytes (lpInput() As Byte, lpKey() As Byte, lpIV() As Byte, szAlgModePad As String, Optional nOptions As Long = 0) As Byte()

.NET Equivalent

Cipher.Decrypt Method (Byte[], Byte[], Byte[], CipherAlgorithm, Mode, Padding, Cipher.Opts)

C++ (STL) Equivalent

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)

Python Equivalent

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)

Remarks

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.

** For ECB and CBC cipher modes, any padding must be removed. To specify the length of lpOutput you can either
  1. [ORIGINAL METHOD] specify the output length of lpOutput equal to the length of the input then truncate the result to the correct length.
  2. [NEW in v12.3] do a first pass setting nOutBytes to zero or lpOutput to 0 or NULL to find the exact decrypted length.
See the examples below. In both cases you may need to cope with the special case where the encrypted output is the empty string, a zero-length byte array.

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".

Examples

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>'

Example (VBA wrapper function)

See example for VBA wrapper cipherEncryptBytes in CIPHER_EncryptBytes.

See Also

CIPHER_EncryptBytes

[Contents] [Index]

[PREV: CIPHER_DecryptAEAD...]   [Contents]   [Index]   
   [NEXT: CIPHER_DecryptBytes2...]

Copyright © 2004-24 D.I. Management Services Pty Ltd. All rights reserved. Generated 2024-09-23T07:52:09Z.