Specialist options have been added to the CryptoSys PKI Toolkit [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 errors in 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.
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. However, it is still meant to be secure when used to encode a message digest, as done in the Autack method. Look, banks in certain Scandinavian countries still use this method, so it must be secure, yes?
This sample code in VB6/VBA shows how to sign and verify a message using Autack.
Public Function Create_Autack_Signature(strData As String, strXmlPrivate As String) As String ' INPUT: data as text string; RSA private key in XML format. ' OUTPUT: RSA/ISO9796-1 signature in hex-encoded form (as the data will be represented in the AUTACK message) ' or empty string on error. ' REMARKS: uses SHA-1 as message digest hash algorithm. Dim strPrivateKey As String Dim klen As Long Dim mlen As Long Dim blen As Long Dim dlen As Long Dim r As Long Dim nKeyBits As Long Dim abData() As Byte Dim abDigest() As Byte Dim abBlock() As Byte Dim strHexSig As String ' 1. Read in RSA private key from XML klen = RSA_FromXMLString("", 0, strXmlPrivate, 0) Debug.Print "RSA_FromXMLString returns " & klen & " (expecting >0)" If klen <= 0 Then Exit Function strPrivateKey = String(klen, " ") klen = RSA_FromXMLString(strPrivateKey, Len(strPrivateKey), strXmlPrivate, 0) nKeyBits = RSA_KeyBits(strPrivateKey) Debug.Print "RSA key length=" & nKeyBits & " bits" ' 2. Make message digest hash of input data Debug.Print "Input data='" & strData & "'" ' Convert string to an array of bytes abData = StrConv(strData, vbFromUnicode) mlen = UBound(abData) + 1 ' Allocate space for digest byte array ReDim abDigest(PKI_SHA1_BYTES - 1) ' Compute SHA-1 digest using byte array as input dlen = HASH_Bytes(abDigest(0), PKI_SHA1_BYTES, abData(0), mlen, PKI_HASH_SHA1) Debug.Print "HASH_Bytes returns " & dlen & " (expecting " & PKI_SHA1_BYTES & ")" Debug.Print "Hash=" & cnvHexStrFromBytes(abDigest) ' 3. Encapsulate hash digest in ISO9796-1 encoding ' -- we need a block of the same length as the key in bytes 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) ' 4. 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 ' 5. Convert to hex encoding strHexSig = cnvHexStrFromBytes(abBlock) ' 6. Output signature as a hex string Debug.Print "Signature=" & vbCrLf & strHexSig Create_Autack_Signature = strHexSig ' Clean up Call wipeBytes(abData) Call wipeBytes(abDigest) Call wipeBytes(abBlock) Call wipeString(strPrivateKey) End Function Public Function Verify_Autack_Signature(strHexSig As String, strXmlPublic As String, strData As String) As String ' INPUT: Signature in hex format; RSA public key in XML format; input data as recovered from message. ' OUTPUT: Recovered message digest if validated, or "**INVALID SIGNATURE" if signature is invalid in any way Dim strPublicKey As String Dim klen As Long Dim mlen As Long Dim blen As Long Dim dlen As Long Dim r As Long Dim nKeyBits As Long Dim abBlock() As Byte Dim abExtracted() As Byte Dim elen As Long Dim strHexDigest As String Verify_Autack_Signature = "**INVALID SIGNATURE" ' Guilty until proven innocent ' 1. Read in RSA public key from XML klen = RSA_FromXMLString("", 0, strXmlPublic, 0) Debug.Print "RSA_FromXMLString returns " & klen & " (expecting >0)" If klen <= 0 Then Exit Function strPublicKey = String(klen, " ") klen = RSA_FromXMLString(strPublicKey, Len(strPublicKey), strXmlPublic, 0) nKeyBits = RSA_KeyBits(strPublicKey) Debug.Print "RSA key length=" & nKeyBits & " bits" ' 2. Convert hex input to byte array abBlock = cnvBytesFromHexStr(strHexSig) Debug.Print "Signature input=" & vbCrLf & cnvHexStrFromBytes(abBlock) ' 3. Decrypt block with RSA public key blen = RSA_KeyBytes(strPublicKey) ' 3a. Check lengths match If blen <> UBound(abBlock) + 1 Then Debug.Print "ERROR: signature does not match key size in bytes" Exit Function End If ' -- use special ISO9796/X9.31/P1363-RSA2 method with magic value 0x6 r = RSA_RawPublic(abBlock(0), blen, strPublicKey, &H6) Debug.Print "RSA_RawPublic returns " & r & " (expecting 0)" If (r <> 0) Then Exit Function Debug.Print "Decrypted block=" & vbCrLf & cnvHexStrFromBytes(abBlock) ' 4. Extract message digest from ISO9796-encoded block elen = RSA_DecodeMsg(0, 0, abBlock(0), blen, PKI_EMSIG_ISO9796 + nKeyBits) Debug.Print "RSA_DecodeMsg returns " & elen & " (expecting >=0)" If elen < 0 Then Exit Function ReDim abExtracted(elen - 1) elen = RSA_DecodeMsg(abExtracted(0), elen, abBlock(0), blen, PKI_EMSIG_ISO9796 + nKeyBits) Debug.Print "Extracted hash=" & cnvHexStrFromBytes(abExtracted) ' 5. Create message digest hash in hex of data, recovered independently Debug.Print "Input data='" & strData & "'" strHexDigest = String(PKI_SHA1_CHARS, " ") r = HASH_HexFromString(strHexDigest, Len(strHexDigest), strData, Len(strData), PKI_HASH_SHA1) Debug.Print "HASH_HexFromString returns " & r & " (expecting " & PKI_SHA1_CHARS & ")" If r < 0 Then Exit Function Debug.Print "Computed hash= " & strHexDigest ' 6. Compare hash digests If UCase(strHexDigest) = cnvHexStrFromBytes(abExtracted) Then Debug.Print "OK, signature is verified" Verify_Autack_Signature = cnvHexStrFromBytes(abExtracted) Else Debug.Print "ERROR: signature is invalid" End If ' Clean up Call wipeBytes(abExtracted) Call wipeBytes(abBlock) Call wipeString(strPublicKey) Call wipeString(strHexDigest) End Function Public Sub Create_Autack_Signature_Example_2() ' Ref: EDIFACT, Section 12.9 2nd Worked Example Dim strXmlPrivate As String Dim strData As String Dim strHexSig As String ' RSA Private Key in (short) XML format ' CAUTION: this is NOT SECURE! The <D> part should be kept secret. strXmlPrivate = "<RSAKeyPair>" & _ "<Modulus EncodingType='hexBinary'>" & _ "A59FBFE322244760E5B430B197967FDCF240D6B134D0F3783EDE652B565AC9C6" & _ "105768F11EE59AED359ED6DB6CE6AFC84233F35B60895B90AF85A66E598C15CE" & _ "FB860EA37CCEDB4A45B4C0594974EB76BC955C43B56B17940DFDCAB3E0C03F49" & _ "A308835772405E74085BF59FBA726969CBE348DAB6F9456DA57B40B64E6E3C65</Modulus>" & _ "<Exponent EncodingType='hexBinary'>010001</Exponent>" & _ "<D EncodingType='hexBinary'>" & _ "244FFDD97DED0FD4441089638A7D85FBAA86823BB87D7E7FF4E2BC322FFCF843" & _ "AB660ABD60DD8CE5E8AD72648A001AF6B06324FE3A106B89B19DFF232F116A5F" & _ "4C7151C38D4A132E0EEBC55EC0DC44EBE0CCBA8FCACB6C93F32997DAD8B9ACEA" & _ "B4BEC5D4A1F38A2218337C8C92D301C433A7E02EB4A456F5DE83AE1AD76E3D31</D>" & _ "</RSAKeyPair>" strData = "abc" strHexSig = Create_Autack_Signature(strData, strXmlPrivate) Debug.Print "Create_Autack_Signature result = '" & strHexSig & "'" End Sub Public Sub Verify_Autack_Signature_Example_5() ' Ref: EDIFACT, Section 12.9 5th Worked Example Dim strXmlPublic As String Dim strHexSig As String Dim strData As String Dim strResult As String ' RSA Public Key in XML format ' (unlike the private key, these parts are quite safe to make public) strXmlPublic = "<RSAKeyValue>" & _ "<Modulus EncodingType='hexBinary'>" & _ "A59FBFE322244760E5B430B197967FDCF240D6B134D0F3783EDE652B565AC9C6" & _ "105768F11EE59AED359ED6DB6CE6AFC84233F35B60895B90AF85A66E598C15CE" & _ "FB860EA37CCEDB4A45B4C0594974EB76BC955C43B56B17940DFDCAB3E0C03F49" & _ "A308835772405E74085BF59FBA726969CBE348DAB6F9456DA57B40B64E6E3C65</Modulus>" & _ "<Exponent EncodingType='hexBinary'>010001</Exponent>" & _ "</RSAKeyValue>" strHexSig = _ "4897C41FFCB27C4B77F0711890C5C48E9C42AE5A1548E1A4653CDF444C60350F" & _ "635A16393D5862DCBD83EF3727435B750CE889EB3C48C02EA0B14F6F6B4BA0D1" & _ "E16A010D42830110AB36AB183F2976B784656D4272A6215A44EAA504610C59AC" & _ "C615E661BE4EC5ACE09B8D9DCE165F0CE71AE8743266ED2F20F35862B3C9252D" strData = "abc" ' Recovered independently by receiver strResult = Verify_Autack_Signature(strHexSig, strXmlPublic, strData) Debug.Print "Verify_Autack_Signature result = '" & strResult & "'" End Sub
For more information or to comment on this page, please send us a message.
This page first published 17 February 2009. Last updated 30 June 2020.
Problems with the EDIFACT test vectors
From us to a client in Norway:
And their reply:
Make your own judgement.