Skip to main content

Notifications

Announcements

No record found.

Dynamics 365 Community / Blogs / Rashed Amini / Encryption and signing of f...

Encryption and signing of files in NAV

Rashed Profile Picture Rashed 3,765

One of my projects involved integrating with a Bank.  The requirements were to send NAV payments electronically to the bank.  In US companies still send payment through Check.  This customer was writing about 1000 checks per week and although I had automated the printing of the check, they still had to fold them and put them in envelop.  They also had other payment types, such as Wire and ACH that they were submitting manually. The file structure was ISO 20022 Payments message xml Files. 

You can read more about it here https://www.iso20022.org/payments_messages.page.

 The client is on version 2009.  Newer version of NAV have ISO 20022 built.  I haven’t looked at it but it I wonder why it’s for European banks, when US Bank is using it as well. I’m not going to talk about the xml file or the ISO file structure.  I’m going to talk about the transmitting of the file.

Once the file is created, it needs to be transmitted to bank.  Before submitting the file needed to be digitally signed with Self signed X509 Certificate.

After some research, I found Bouncy Castle. Here is their website.

http://www.bouncycastle.org/csharp/

 

After some additional research, I built csharp assembly that can be called from NAV to sign a file with a  certificate.  

 

Here is the code for the cshap DLL. 

 

using System;
using System.Collections;
using System.IO;
using System.Text;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.Bcpg;
using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Utilities.IO;

namespace BountyCastlePGP
{
    public static class SignOnly
    {
        public static void SignFile(string fileName, string keyInFileName, string SignedFileName, string passphrase)
        {
            bool armor = false;
            bool compress = true;
            Stream keyIn = File.OpenRead(keyInFileName);
            Stream outputStream = File.Create(SignedFileName);
            if (armor)
            {
                outputStream = new ArmoredOutputStream(outputStream);
            }

            PgpSecretKey pgpSec = ReadSigningSecretKey(keyIn);
            PgpPrivateKey pgpPrivKey = pgpSec.ExtractPrivateKey(passphrase.ToCharArray());
            PgpSignatureGenerator sGen = new PgpSignatureGenerator(pgpSec.PublicKey.Algorithm, HashAlgorithmTag.Sha1);

            sGen.InitSign(PgpSignature.BinaryDocument, pgpPrivKey);
            foreach (string userId in pgpSec.PublicKey.GetUserIds())
            {
                PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator();
                spGen.SetSignerUserId(false, userId);
                sGen.SetHashedSubpackets(spGen.Generate());
                // Just the first one!
                break;
            }

            Stream cOut = outputStream;
            PgpCompressedDataGenerator cGen = null;
            if (compress)
            {
                cGen = new PgpCompressedDataGenerator(CompressionAlgorithmTag.ZLib);

                cOut = cGen.Open(cOut);
            }

            BcpgOutputStream bOut = new BcpgOutputStream(cOut);

            sGen.GenerateOnePassVersion(false).Encode(bOut);

            FileInfo file = new FileInfo(fileName);
            PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
            Stream lOut = lGen.Open(bOut, PgpLiteralData.Binary, file);
            FileStream fIn = file.OpenRead();
            int ch = 0;

            while ((ch = fIn.ReadByte()) >= 0)
            {
                lOut.WriteByte((byte)ch);
                sGen.Update((byte)ch);
            }

            fIn.Close();
            lGen.Close();

            sGen.Generate().Encode(bOut);

            if (cGen != null)
            {
                cGen.Close();
            }

            if (armor)
            {
                outputStream.Close();
            }
            keyIn.Close();
            outputStream.Close();
        }


        public static PgpSecretKey ReadSigningSecretKey(Stream inStream)
        {
            PgpSecretKeyRingBundle pgpSec = CreatePgpSecretKeyRingBundle(inStream);
            PgpSecretKey key = null;
            IEnumerator rIt = pgpSec.GetKeyRings().GetEnumerator();
            while (key == null && rIt.MoveNext())
            {
                PgpSecretKeyRing kRing = (PgpSecretKeyRing)rIt.Current;
                IEnumerator kIt = kRing.GetSecretKeys().GetEnumerator();
                while (key == null && kIt.MoveNext())
                {
                    PgpSecretKey k = (PgpSecretKey)kIt.Current;
                    if (k.IsSigningKey)
                        key = k;
                }
            }

            if (key == null)
                throw new PgpException("Can't find signing key in key ring.");
            else
                return key;
        }

        public static PgpSecretKeyRingBundle CreatePgpSecretKeyRingBundle(System.IO.Stream keyInStream)
        {
            return new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(keyInStream));
        }
    }
}

 

 

And this here is how to call it from NAV.

 

BountyPGP.SignFile(FileName,PrivateKeyFile,NewgpgFileName,PassPhrase);

Comments

*This post is locked for comments