Absent Member.
Absent Member.
1683 views

Encrypt And Un-Encrypt a Print file

Hi,

I have the following code that encrypts and then i can un-encrypt this file, which works file with text files i.e. readable characters.

However if i try to do this with a stored printed data file that contains unreadable characters it produces garbage.

Is there any way to do this using this .NET class?

method-id "EncryptFile" public static.
01 ls-fsInput type "System.IO.FileStream".
01 ls-fsEncrypted type "System.IO.FileStream".
01 ls-des type "System.Security.Cryptography.DESCryptoServiceProvider".
01 ls-desencrypt type "System.Security.Cryptography.ICryptoTransform".
01 ls-cryptostream type "System.Security.Cryptography.CryptoStream".
01 ls-bytearrayinput type "System.Byte" occurs any.
01 ls-len binary-long.
01 ls-ToBase64Transform type "System.Security.Cryptography.ToBase64Transform".
procedure division using by value lnk-inputfile as string
lnk-Outputfile as string
lnk-key as string.

set ls-fsInput to type "System.IO.FileStream"::"New"(lnk-inputfile , type "System.IO.FileMode"::"Open" , type "System.IO.FileAccess"::"Read")
set ls-fsEncrypted to type "System.IO.FileStream"::"New"(lnk-Outputfile , type "System.IO.FileMode"::"Create" , type "System.IO.FileAccess"::"Write")

set ls-des to type "System.Security.Cryptography.DESCryptoServiceProvider"::"New"()
*
* *> Set secret key for DES algorithm.
* *> A 64-bit key and an IV are required for this provider.
*>set ls-DES::"Key" to type "System.Text.ASCIIEncoding"::"ASCII"::"GetBytes"(lnk-Key)
set ls-DES::"Key" to type "System.Text.UTF8Encoding"::"UTF8"::"GetBytes"(lnk-Key)
*
* *> Set the initialization vector.
*>set ls-DES::"IV" to type "System.Text.ASCIIEncoding"::"ASCII"::"GetBytes"(lnk-Key)
set ls-DES::"IV" to type "System.Text.UTF8Encoding"::"UTF8"::"GetBytes"(lnk-Key)
*
* *> Create the DES encryptor from this instance.
set ls-desencrypt to ls-DES::"CreateEncryptor"()
*
* *> Create the crypto stream that transforms the file stream by using DES encryption.
set ls-cryptostream to type "System.Security.Cryptography.CryptoStream"::"New"(ls-fsEncrypted , ls-desencrypt , type "System.Security.Cryptography.CryptoStreamMode"::"Write")
*
* *> Read the file text to the byte array.
compute ls-len = ls-fsInput::"Length"
set size of ls-bytearrayinput to ls-len
invoke ls-fsInput::"Read"(ls-bytearrayinput , 0 , ls-bytearrayinput::"Length")
* *> Write out the DES encrypted file.
invoke ls-cryptostream::"Write"(ls-bytearrayinput , 0 , ls-bytearrayinput::"Length")
invoke ls-cryptostream::"Close"()

goback.
end method "EncryptFile".

method-id "DecryptFile" public static.
01 ls-fsRead type "System.IO.FileStream".
01 ls-fsdecrypted type "System.IO.StreamWriter".
01 ls-desdecrypt type "System.Security.Cryptography.ICryptoTransform".
01 ls-des type "System.Security.Cryptography.DESCryptoServiceProvider".
01 ls-cryptostream type "System.Security.Cryptography.CryptoStream".
01 ls-bytearrayinput type "System.Byte" occurs any.
01 ls-len binary-long.
procedure division using by value lnk-inputfile as string
lnk-Outputfile as string
lnk-key as string.

set ls-fsRead to type "System.IO.FileStream"::"New"(lnk-inputfile , type "System.IO.FileMode"::"Open" , type "System.IO.FileAccess"::"Read")

set ls-des to type "System.Security.Cryptography.DESCryptoServiceProvider"::"New"()
*> Set secret key for DES algorithm.
*> A 64-bit key and an IV are required for this provider.
*>set ls-DES::"Key" to type "System.Text.ASCIIEncoding"::"ASCII"::"GetBytes"(lnk-Key)
set ls-DES::"Key" to type "System.Text.UTF8Encoding"::"UTF8"::"GetBytes"(lnk-Key)

*> Set the initialization vector.
*>set ls-DES::"IV" to type "System.Text.ASCIIEncoding"::"ASCII"::"GetBytes"(lnk-Key)
set ls-DES::"IV" to type "System.Text.UTF8Encoding"::"UTF8"::"GetBytes"(lnk-Key)

*> Create the DES decryptor from the DES instance.
set ls-desdecrypt to ls-des::"CreateDecryptor"()

*> Create the crypto stream set to read and to do a DES decryption transform on incoming bytes.

set ls-cryptostream to type "System.Security.Cryptography.CryptoStream"::"New"(ls-fsRead , ls-desdecrypt , type "System.Security.Cryptography.CryptoStreamMode"::"Read")

*> Print out the contents of the decrypted file.
set ls-fsDecrypted to type "System.IO.StreamWriter"::"New"(lnk-OutputFile)
invoke ls-fsDecrypted::"Write"(type "System.IO.StreamReader"::"New"(ls-cryptostream)::"ReadToEnd")
invoke ls-fsDecrypted::"Flush"()
invoke ls-fsDecrypted::"Close"()

goback.
end method "DecryptFile".

0 Likes
3 Replies
Micro Focus Expert
Micro Focus Expert

I'm not immediately seeing the problem. I'll have to take a closer look.

Unless you're using a very old version of COBOL for .NET, you don't need quotes around type and method names. That would make your source code easier to read.

0 Likes
Micro Focus Expert
Micro Focus Expert

One problem that I noticed while rewriting this is that you don't validate the length of the key and IV, both of which must be ls-DES::BlockSize. I've fixed this (trivially) in my version.

Using the key as the IV is a Bad Idea, in terms of security; but I have no idea what your application or threat model is, so I don't know whether that's relevant. (Using DES is itself a Bad Idea for many applications.)

0 Likes
Micro Focus Expert
Micro Focus Expert

Well, I have my version working, and it doesn't appear to have a problem with files of any sort.


Here's the source.


      $set sourceformat(variable)
      $set ilusing(System)
      $set ilusing(System.IO)
      $set ilusing(System.Security.Cryptography)
      $set ilusing(System.Text)

       class-id descrypt.

       1 inputFile type FileStream static.
       1 outputFile type FileStream static.
       1 des type DESCryptoServiceProvider static value new DESCryptoServiceProvider.

       method-id Main(args as string occurs any) static.
           if args::Length <> 4
               invoke self::Syntax
           end-if
           declare encrypting as condition-value
           evaluate args(1)
           when "encrypt"
               set encrypting to true
           when "decrypt"
               set encrypting to false
           when other
               invoke self::Syntax
           end-evaluate

           set inputFile to new FileStream(args(3), type FileMode::Open, type FileAccess::Read)
           set outputFile to new FileStream(args(4), type FileMode::Create, type FileAccess::Write)

           declare keySize as binary-long = des::BlockSize / 8
           declare keyBlock as binary-char unsigned occurs any
           set size of keyBlock to keySize
           declare keyBytes = type UTF8Encoding::UTF8::GetBytes(args(2))
           declare copyLen = function min(size of keyBlock, size of keyBytes)
           invoke type Array::Copy(keyBytes, 0, keyBlock, 0, copyLen)
           set des::Key des::IV to keyBlock
           set des::IV to keyBlock

           if encrypting
               invoke self::Encrypt
           else
               invoke self::Decrypt
           end-if
       end method Main.

       method-id Syntax static.
           display "Usage: descrypt encrypt|decrypt key input-file output-file"
           invoke type Environment::Exit(1)
       end method Syntax.

       method-id Encrypt static.
           declare cryptoStream = new CryptoStream(outputFile, des::CreateEncryptor, type CryptoStreamMode::Write)
           invoke inputFile::CopyTo(cryptoStream)
           invoke cryptoStream::Close
           invoke outputFile::Close
       end method Encrypt.

       method-id Decrypt static.
           declare cryptoStream = new CryptoStream(inputFile, des::CreateDecryptor, type CryptoStreamMode::Read)
           invoke cryptoStream::CopyTo(outputFile)
           invoke cryptoStream::Close
           invoke outputFile::Close
       end method Decrypt.

       end class descrypt.


Some things to note:

  • This was tested with Enterprise Developer 2.2 Update 1 and .NET Framework 4.5.
  • I've refactored common code into the Main method.
  • Type and method names do not need to be quoted in current versions of managed COBOL.
  • Use the new operator rather than invoking a constructor directly (type X::New(...)).
  • The CopyTo method (of Stream and its subclasses) is the simplest way to read an entire stream and write it to another stream.
  • The COBOL type binary-char unsigned is the same as the .NET type Byte.
  • My Main method creates an array of the correct size, then copies the key bytes into it, to ensure the Key and IV properties receive an array of the correct size.

0 Likes
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.