CryptoSys Home > PKI > AUTACK messages and ISO/IEC 9796-1 signatures

AUTACK messages and ISO/IEC 9796-1 signatures


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:

  1. Create the message digest hash of the message to be signed using HASH_Bytes() function.
  2. Encode (encapsulate) this message digest in ISO 9796-1 format using RSA_EncodeMsg().
  3. Sign, i.e. encrypt with the private RSA key, using RSA_RawPrivate().

Specific changes to enable this:

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

Problems with the EDIFACT test vectors

From us to a client in Norway:

One thing we did find after a *lot* of effort is that most of the examples in the EDIFACT (d6) document are actually wrong!

We could reproduce the first signature they give (the 2nd Working Example in section 12 -- the one for "abc"), but could not reproduce the other two. Working backwards, we eventually managed to prove that they have actually made a mistake. It looks like they have used a length parameter of 16 for the ISO9796-1 encapsulation process instead of the 20 required for SHA-1. If you get just one bit wrong in the encapsulation process then the entire 128-byte signature will be completely different.

This just shows how many people have actually read that document and tested the examples.

And their reply:

I am sorry that you had extra work due to lousy examples. I do not know how they have managed to work through this in other projects with bad examples, but it is a shame that they are not able to present the correct examples. After some questions both to the actual bank and to the Norwegian bank standardization committee, I realize that none of them has knowledge in this subject. They have selected a standard, and have no working experience or information about it.

Make your own judgement.


References

Contact

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.