Cybersecurity of External Streaming Data - Non-repudiation

Preface

When talking about documents such as a wire transfer order, there is no need to provide any special justification that the recipient of such a document will be vitally interested in being able to determine that the document has been issued by an authorized person, for example by the owner of the account for which the order was issued.

Because we use file systems and transfer bitstream data over computer networks streaming data security must inherently be the subject of our particular concern. In this article, the discussion on cryptographic security is continued in the context of non-repudiation. Non-repudiation can be achieved by providing a way to verify that the sender of a message is who claims to be and that the message has not been altered during transmission. To achieve this protection a digital signature is applied. The digital signature is a cryptographic technique used to ensure the authenticity and integrity of a bitstream.

We have already learned about the hash function to protect bitstream integrity (Cybersecurity of External Streaming Data - Integrity). However, there is still a problem with how to distribute its result so that in different places of the IT system, and different locations in the world this hash value can be used to check the integrity of a bitstream. Bitstream integrity refers to the assurance that the bitstream remains intact during transmission or storage. It ensures that each bit in the data stream retains its original value without corruption or errors. The previous article Cybersecurity of External Streaming  Data  - Confidentiality` addresses symmetric encryption, in which we use identical keys by the encryption and decryption inter-operating parties. Again, we have the problem of distributing these keys among the authorized users who have the right to access the information represented by this stream. There is another problem with the use of symmetric encryption, namely scalability. It consists of the fact that the number of keys that we need to manage for encryption and decryption increases rapidly, that is, it increases with the square of the number of parties that participate in sharing data.

To implement a digital signature, the sender uses a private key to create a unique digital signature for the message. This private key is known only to the sender and is kept confidential. The recipient, in turn, can verify the signature using the sender's public key. The public key is widely distributed and can be freely shared.

If the digital signature is valid, it confirms that the bitstream is indeed signed by the holder of the private key associated with the public key used for verification. The digital signature also ensures that the content of the bitstream has not been altered since the signature was created. Even a small change in the bitstream would result in a different signature.

Digital signatures are widely used in electronic transactions, software distribution, and other scenarios where ensuring the origin and integrity of bitstreams is crucial. Let's check how asymmetric encryption could be implemented in this article. First of all, I propose to deal with the confirmation of authorship. This issue has been associated with the topic of ensuring bitstream integrity. So let's move on to how a digital signature works, and how we ensure that the document's author cannot deny that he is the author.

Compliance with Domain-specific Language

If a bitstream to be signed is compliant with a domain-specific language (for example XML), by design the inserted text to this bitstream must not break compliance with this language. For example, consider the catalog.example.xml document that we already used in examples.

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="catalog.xslt"?>
<Catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
         xmlns="http://Viculu34.org/Catalog.xsd"
         >
  <CD>
    <Title>Empire Burlesque</Title>
    <Artist>Bob Dylan</Artist>
    <Country>USA</Country>
    <Company>Columbia</Company>
    <Price>10.90</Price>
    <Year>1985</Year>
  </CD>
  <CD>
    <Title>Hide your heart</Title>
    <Artist>Bonnie Tyler</Artist>
    <Country>UK</Country>
    <Company>CBS Records</Company>
    <Price>9.90</Price>
    <Year>1988</Year>
  </CD>
</Catalog>

Let's try to add a free-formatted text at the end of this document, for example, a previously calculated hash value (Cybersecurity of External Streaming Data - Integrity) expressed as hexadecimal text encoded using ASCII standard. Well, of course, we can easily predict the result. There is a syntax error reported, hence it can be stated that this document is no longer an XML document. Because the syntax is not correct it is not possible to recover the meaning of this document as one whole including added text. It is simply a free text and is not suitable for further processing when we expect the document to follow XML syntax rules.

What can we do? We can surround this text with an element markup, which is called for example Hash. As a result, we no longer have an XML syntax error, but we do have an error that such an element does not exist according to the schema we have defined. We can dumb down this document again and remove references to the schema, which defines what an XML document should contain. But this again leads to further consequences, such that if we expect that this document is compliant with a certain schema, then, as a consequence, this document is rejected because the schema is not defined for it. I would like us to remember this when following the method of implementing a digital signature. It will be vital to us.

Signing Process

First, let me recall the three goals we have.

  1. The first one is to ensure that all users of the source bitstream can verify that the stream was not modified while it was being archived or transmitted.
  2. The second goal is to safeguard information from unauthorized access, ensuring confidentiality. This goal can be enforced using the encryption already examined provided that the key distribution will support this.
  3. Last but not least purpose is to confirm authorship, so all users of this stream can determine who created this stream and who is responsible for its content. This goal we call non-repudiation of the author. In this case, let me remind you of an example involving a wire transfer. It would have been much better for the bank to have been sure that the person issuing the wire transfer order would not be able to deny authorship of the order and blame someone who transferred the money.

The following diagram shows how to achieve authorship non-repudiation of a bitstream.

Bitstream

In the first step, we calculate the hash (Cybersecurity of External Streaming Data - Integrity), just like before. But then we encrypt this hash using a private key, which is assumed to be assigned to a certain identity, which is to be exclusively at the disposal of this identity. So, at least theoretically, no one else can use this key. If we encrypt the hash using a private key and asymmetric algorithm, the result is called a signature. We can therefore attach this signature to the original bitstream, archive, or send the result to another place over a network.

To check the bitstream integrity and authorship at the final location, we can first recalculate the hash value for the part that constitutes the source bitstream. This hash should be the same as the one recovered from the signature. To recover the hash value, namely, determine its initial value, the signature can be decrypted using the public key. The public key is associated with the private key (both are the keys pair), and we will then obtain the decrypted hash value calculated by the author of the bitstream. To check the correctness of the bitstream before further calculation, we can now compare the decrypted initial hash value with the hash value that is calculated after receiving the bitstream. If these two hash values are the same, it means that the input bitstream has not been affected because the hash value is still the same. Since we used a public key that is paired with a private key, we can also conclude that a specific identity created this stream. For any other identity, this decryption operation will not produce an identical hash value.

And now the last thing is how to ensure non-repudiation. How to ensure that the person who originally signed this bitstream will not say after some time that it is not him/she, that it is someone else? We can do it only after ensuring that the public key has been provided by a public benefit organization, just like an ID that confirms our identity. This means that we trust a certain organization that issued this key. This key is made available to us in the context of personal data, data that describes the identity, and therefore, based on this trust, we can conclude that this is a specific person, a specific identity.

Creation of Keys Example

Let's move on to discussing how to implement this scenario using program text. As we can see from the description of this scenario, one of the important problems we have is creating and distributing keys. Hence, the first method CreateRSACryptoServiceKeys is an example of how to generate keys and to point out how these keys may be distributed as an XML text.

    public static (RSAParameters parameters, string publicKey, string privatePublicKeys) CreateRSACryptoServiceKeys()
    {
      using (RSACryptoServiceProvider _rsa = new RSACryptoServiceProvider(2048))
      {
        RSAParameters _parameters = _rsa.ExportParameters(true);
        string _public = _rsa.ToXmlString(false);
        string _both = _rsa.ToXmlString(true);
        return (_parameters, _public, _both);
      }
    }

Of course, the topic related to key distribution - in general - is far beyond the scope of this article, therefore let me encourage you to check out other publications at this point. In this test, I use a method that generates keys. Let's go to its definition and see that in the first step, an object RSACryptoServiceProvider is created for which we define the key length. This is a parameter that also determines the strength of security, but at the same time, it has some negative impact on the performance of this process. Depending on the equipment we have, this number should not be outsized here.

Once this object is created, the keys are generated. We can use these keys and we have three options. First, we can return the keys as an RSParameters object. An instance of this class contains both private and public keys but is intended only for use inside the application. It is not intended to be used for key distribution outside of the application hosting realm. The next two lines show how to generate XML text that contains the keys. The XML form is suitable for archiving or distributing the keys over the network. Anyway, in the investigated sample, all three forms of keys are returned as a result of this method. It is a redundant solution to show only possible implementations.

Let's go to the CreateRSACryptoServiceKeysTest test method, where we check that the first variable is not null, so an object of the RSAParameters class is returned.

    [TestMethod]
    public void CreateRSACryptoServiceKeysTest()
    {
      (RSAParameters parameters, string publicKey, string privatePublicKeys) = CryptographyHelpers.CreateRSACryptoServiceKeys();
      Assert.IsNotNull(parameters);
      Assert.AreNotEqual<string>(publicKey, privatePublicKeys);
      Debug.WriteLine(publicKey);
      Debug.WriteLine(string.Empty);
      Debug.WriteLine(privatePublicKeys);
    }

We further check that the content of the XML document (just a text) that contains only the public key PubliKey.xml compared to the one that contains the public key and private key, are not the same. From the point of view of testing, these operations are not important, but they show how the CreateRSACryptoServiceKeys method works.

The XML document that contains both the public and the private keys is located in the file PubliPrivateKeys.xml. Of course, in the case of a private key, identity information is not important because, by design, the private key is only used by the owner.

<?xml version="1.0" encoding="utf-8" ?>
<RSAKeyValue>
  <Modulus>2oFiov7xnJGWf++WBHOdkzp1IHzNZRXhFL0MDFxBIJQvlm3p80WwhoxUQVawJTGRbdGMutOHHOTj+uxFAFlmKrvcaltfRV/rq0Z43LeIbfeX8uwsr10lnxqLhONlP+kY9+RiAartXP3nTG88gFah9j7WrSmlrJWvSCD0lZvUxcuFioXXZw8UQ43046SWhXMYABkZ+1RYKsSjfz80/TITuR0kkY3wIwHiIWhZUjWwNxEh0CLmM06oFLjSKgZwe4UyhCRlg3iXNK3CeMC+ToSyo+lehGnWD226uNECvB3SWC4YN7r96u0xrQcf0//x6nzSdEArohFVyGgB3yb6rlFLjw==</Modulus>
  <Exponent>AQAB</Exponent>
  <P>9A0KwiudcPWDrwVIq+2ANkuu7IILGf9D94U+qViZAKclqxc9+7UcCeP1a0LCmTiJCVLvNam4ISvU3I7rBnE46cFvJ7c+9SIQZTfb9HOFB78Q5+ulx9k9lv8VKypfuBynoV15f3OHkr2FddSsyKf4EuF20UVWsV8YSJ+iJ5gCc8M=</P>
  <Q>5TQnMXCb2DjgY1sGfQgaOtVOakjemhkGUeKNJ+4ptcTUHp/hZWPtZw53kFdje1fZprDdMqKIxM2XQI+NDm2WIDnBOsXQK+K1LAh+4XXEBS+0HcPqqMW8itttOXLeoiNDXWwYWQ5/6UOLUC1ZGyjynE89FQKpyp2i6pHWhocuCEU=</Q>
  <DP>xoXhbYfLH7snrnSu4+RjukcgeRVj8Hbck/mYumrus0BEfQOAEUQHFeiQl/sLj1YU6zfCjLWNqbYdBnlfp7LsaAJI6FbA6OkXyy6ARz69RUrgdrgS+Bm4Zx8C2kUy7fKpTbNbBRk2fGCcsvgYwXUZcEplu+AaoFhJybHJV0npHL8=</DP>
  <DQ>LH4tRYmolxajaGYZIlhaTyVtLXCr1ZoaAfdKk3/GFQT6cF9076uwQBss1pZAN4dcNuGKbvPiPOH0BJJZPX3EcMkFW5VezcYaiUu05atou+EAw+5uNQj9iq8Byu8jjLHvt8juCQuphOyZtJy4+W6/edxf7R4xO6XSJFrfHApNw0k=</DQ>
  <InverseQ>0op7bysIJnOESr0FO8JxVh85wK0dX4vC89prAzUPc2YBsrf4aW/tSewcHDtGvx0fuUZEiJcyzunho+cuuC3SzMZK2CXTJWIvR/qTuD5bjzWm3CNKP+AdvLTaCQ78M/fx7D96bhPECsy2rkwh3iBCNs0YytrGkmeij9V6Pe0ZYRk=</InverseQ>
  <D>QkBexuskGQPvrQTY6KqhiYV9BAezQ0YaA+66G3lRae5ka2kSOWfU+UbNOS5upCheXvzdfbwrSHCCS4+d8Fgq6SQi1cC0p1VJIJpyhQHFBQrAcLB5cAZ/JLmoufc0uOcVYfxGVxkbdUmq+vrzTjp2SzKMZt6s1CJiji0n28DvB7V5XpZoCBVAyT705jtdx/K5zgYd7a036D5e2KNtBWDI2l2w63AAQNaqgsNGjEt3N1fHO1yyOf9q7loYvtNAJcj5i2TpEeWiJy5w1hfYGfG28bB+mrL71dfG7wjJWrUJNdoKeONS63ZS2jwMyeTWp5wuwwlh8cgQMXhJBlJF9lPNeQ==</D>
</RSAKeyValue>

The situation is different when we have a document containing only the public key. PubliKey.xml is an XML document that contains only the public key.

<?xml version="1.0" encoding="utf-8" ?>
<RSAKeyValue>
  <Modulus>2oFiov7xnJGWf++WBHOdkzp1IHzNZRXhFL0MDFxBIJQvlm3p80WwhoxUQVawJTGRbdGMutOHHOTj+uxFAFlmKrvcaltfRV/rq0Z43LeIbfeX8uwsr10lnxqLhONlP+kY9+RiAartXP3nTG88gFah9j7WrSmlrJWvSCD0lZvUxcuFioXXZw8UQ43046SWhXMYABkZ+1RYKsSjfz80/TITuR0kkY3wIwHiIWhZUjWwNxEh0CLmM06oFLjSKgZwe4UyhCRlg3iXNK3CeMC+ToSyo+lehGnWD226uNECvB3SWC4YN7r96u0xrQcf0//x6nzSdEArohFVyGgB3yb6rlFLjw==</Modulus>
  <Exponent>AQAB</Exponent>
</RSAKeyValue>

Since this key will be used by third parties (bitstream users), by design, the distributed document must contain information about the identity to which this public key is associated. Of course, this is not fulfilled here. For this to be true, information about the public key must be added to another document called a certificate. A certificate is a document that has just been issued by a trusted organization. The organization is an office that certifies with its signature that the certificate is authentic and contains correct information. From the certificate itself, we can find out what identity the public key is assigned to. Unfortunately, discussing these issues in detail, as I said earlier, is far beyond the scope of this document.

XML Document Signing Example

Let us now discuss how to implement the operation of signing an XML document and how to encapsulate the obtained signature in this document so as not to violate the rules of syntax control consistent with its schema. We are using XML but the same approach may be applied for any domain-specific language. First, we will need an input file that will serve as a signed source document. For this purpose, the file catalog.example.xml is used. We will also need the keys. We will use the private key to sign the document, precisely to encrypt the hash value calculated for the initial bitstream (Cybersecurity of External Streaming Data - Integrity). We will use the public key to check the validity of the signature, precisely to decrypt the attached signature.

The signing operation is performed in the XmlSignatureTest test method. This operation is implemented in the SignSaveXml method to which we passed the source document to be signed, the keys that will be used for signing, and the name of the document where the signed document is to be saved. In this method, apart from checking the correctness of the input arguments, we create an instance of the RSACryptoServiceProvider class, which is to be used to create a signature so that we can place the signature in this document. Signing itself means that we add a signature in the last instruction. To create this signature, we use the keys that we passed while invoking the method, so this instance is initialized with the keys that were passed here so that the entire signing process takes place using the keys that will be further used to check the signature. Finally, the signed document is saved to a file.

So let's return to the XmlSignatureTest test method. We assume that we have already signed and saved the document in the file and now we can move on to discussing the methods that check the correctness of this document. There are two overloads of the LoadVerifyXml methods.

    public static XmlDocument LoadVerifyXml(string rsaKeys, string fileName)
    {
      #region Check arguments

      if (string.IsNullOrEmpty(rsaKeys))
        throw new ArgumentException($"The {nameof(rsaKeys)} parameter cannot be null");
      if (string.IsNullOrEmpty(fileName))
        throw new ArgumentException($"The {nameof(fileName)} parameter cannot be null");

      #endregion Check arguments

      (XmlDocument _document, SignedXml _signedXml) = LoadSignedXmlFile(fileName);
      using (RSACryptoServiceProvider _provider = new RSACryptoServiceProvider())
      {
        _provider.FromXmlString(rsaKeys);
        if (!_signedXml.CheckSignature(_provider))// Check the signature using custom RSA keys.
          throw new CryptographicException($"Wrong signature of the document.");
      }
      return _document;
    }

    public static XmlDocument LoadVerifyXml(string fileName)
    {
      #region Check arguments

      if (string.IsNullOrEmpty(fileName))
        throw new ArgumentException($"The {nameof(fileName)} parameter cannot be null");

      #endregion Check arguments

      (XmlDocument _document, SignedXml _signedXml) = LoadSignedXmlFile(fileName);
      if (!_signedXml.CheckSignature())// Check the signature and return the result.
        throw new System.Security.Cryptography.CryptographicException($"Wrong signature of the document.");
      return _document;
    }

Calling the first overload, we do not transfer the keys. It is worth emphasizing that the document is loaded and checked using the public key stored in it. With this solution, we do not have to bother providing the public key. Of course, with this type of checking, we cannot confirm the author's identity because anyone can enter such a public key. The only thing we can do is validate whether the document is consistent against this key. The second overload of this method uses the already passed keys and initializes the RSACryptoServiceProvider object, which is used to check the document's authorship.

Finally, let's look at the signed XML document SignedXmlFile.xml. We can see that the Signature element has been added. This document is currently erroneous because it is incompatible with the declared document schema. To fix it, the Signature element has to be removed from the XML document just after validation against the signature, and before using this document, for example for a deserialization operation; i.e. creating a graph of objects based on it.

A Signature element complies with the XML Digital Signature standard, namely XML Signature Syntax and Processing Version 1.1 issued by W3C in 2013. It is used to encapsulate digital signatures within an XML document. The Signature element contains information about the signature, including the cryptographic signature value and details about the key used for signing. Thanks to this it can be easily removed from the XML document before further processing.

Conclusion

We have already learned that there are two types of encryption. In the examples discussed in this article, only the asymmetric encryption method of the bitstreams is the subject of examination. Symmetric encryption has been the subject of the previous article  Cybersecurity of External Streaming Data - Confidentiality covering the confidentiality of bitstreams.

In this article, the discussion on cryptographic security is continued in the context of non-repudiation. Non-repudiation can be achieved by providing a way to verify that the sender of a message is who claims to be and that the message has not been altered. To achieve this protection a digital signature is applied. The digital signature is a cryptographic technique used to ensure the authenticity and integrity of a bitstream.

The digital signature is implemented based on asymmetric encryption. Precisely, not the encryption itself because the performance of asymmetric encryption is not enough compared with the symmetric encryption hence it is only used in selected scenarios. This article explores examples illustrating digital signature scenarios in which asymmetric encryption can and should be used to create a safe hash value interchange channel. Asymmetric encryption is also used to distribute a session key securely. The session key for communication encryption is a temporary cryptographic key used to secure communication between parties to establish a secure session. It is generated for a short duration to be used to establish a secure session allowing for encrypting and decrypting bitstreams exchanged between the interoperable parties. Initially, session keys can be securely exchanged using asymmetric cryptography, where each interoperable party has a pair of public and private keys. The public keys can be exchanged openly, while the private keys are kept secret.

From the preceding discussion, we may conclude that non-repudiation can be implemented only by ensuring that the public keys are provided by a public benefit organization, just like an ID that confirms our identity. This means that we trust a certain organization that issued this key. This key is made available to us in the context of data that describes the identity, and therefore, based on this trust, we can conclude that this is a specific identity.

Using non-repudiation to protect the integrity of text documents the unimportant changes must be considered. Unimportant modifications of a text document typically refer to changes that do not affect the associated meaning of the document. These could include for example adding/removing whitespace characters or comments. Let me stress that the non-repudiation employing digital signature is used to protect the integrity of the bitstream but not to assess equivalent documents. In other words, a zero-tolerance modification strategy is implied at the bitstream level.


Similar Articles