電子發票 QR碼產生用程式碼 C# .NET

來源:財政部
註解:me

使用時注意 namespace


using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;

namespace tw.gov.nat.einvoice.qrutil
{
    class QREncrypter
    {
        /// <summary>
        /// 將發票資訊文字加密成驗證文字
        /// </summary>
        /// <param name="plainText">發票資訊</param>
        /// <param name="AESKey">種子密碼(QRcode)</param>
        /// <returns>加密後的HEX字串</returns>

        public string AESEncrypt(string plainText, string AESKey)
        {
            byte[] bytes = Encoding.Default.GetBytes(plainText);
            ICryptoTransform transform = new RijndaelManaged
            {
                KeySize = 0x80,
                Key = this.convertHexToByte(AESKey),
                BlockSize = 0x80,
                IV = Convert.FromBase64String("Dt8lyToo17X/XkXaQvihuA==")
            }.CreateEncryptor();
            MemoryStream stream = new MemoryStream();
            CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Write);
            stream2.Write(bytes, 0, bytes.Length);
            stream2.FlushFinalBlock();
            stream2.Close();
            return Convert.ToBase64String(stream.ToArray());
        }
        /// <summary>
        /// 轉換HEX值為 Binaries
        /// </summary>
        /// <param name="hexString">HEX字串</param>
        /// <returns>Binaries值</returns>

        private byte[] convertHexToByte(string hexString)
        {
            byte[] buffer = new byte[hexString.Length / 2];
            int index = 0;
            for (int i = 0; i < hexString.Length; i += 2)
            {
                int num3 = Convert.ToInt32(hexString.Substring(i, 2), 0x10);
                buffer[index] = BitConverter.GetBytes(num3)[0];
                index++;
            }
            return buffer;
        }
        /// <summary>
        /// 檢查發票輸入資訊
        /// </summary>
        /// <param name="InvoiceNumber">發票字軌號碼共 10 碼</param>
        /// <param name="InvoiceDate">發票開立年月日(中華民國年份月份日期)共 7 碼</param>
        /// <param name="InvoiceTime">發票開立時間 (24 小時制) 共 6 碼</param>
        /// <param name="RandomNumber">4碼隨機碼</param>
        /// <param name="SalesAmount">以整數方式載入銷售額 (未稅),若無法分離稅項則記載為0</param>
        /// <param name="TaxAmount">以整數方式載入稅額,若無法分離稅項則記載為0</param>
        /// <param name="TotalAmount">整數方式載入總計金額(含稅)</param>
        /// <param name="BuyerIdentifier">買受人統一編號,若買受人為一般消費者,請填入 00000000 8位字串</param>
        /// <param name="RepresentIdentifier">代表店統一編號,電子發票證明聯二維條碼規格已不使用代表店,請填入00000000 8位字串</param>
        /// <param name="SellerIdentifier">銷售店統一編號</param>
        /// <param name="BusinessIdentifier">總機構統一編號,如無總機構請填入銷售店統一編號</param>
        /// <param name="productArray">單項商品資訊</param>
        /// <param name="AESKey">加解密金鑰(QR種子密碼)</param>

        private void inputValidate(string InvoiceNumber,
            string InvoiceDate,
            string InvoiceTime,
            string RandomNumber,
            decimal SalesAmount,
            decimal TaxAmount,
            decimal TotalAmount,
            string BuyerIdentifier,
            string RepresentIdentifier,
            string SellerIdentifier,
            string BusinessIdentifier,
            Array[] productArray,
            string AESKey)
        {
            if (string.IsNullOrEmpty(InvoiceNumber) || (InvoiceNumber.Length != 10))
            {
                throw new Exception("Invaild InvoiceNumber: " + InvoiceNumber);
            }
            if (string.IsNullOrEmpty(InvoiceDate) || (InvoiceDate.Length != 7))
            {
                throw new Exception("Invaild InvoiceDate: " + InvoiceDate);
            }
            try
            {
                long num = long.Parse(InvoiceDate);
                int num2 = int.Parse(InvoiceDate.Substring(3, 2));
                int num3 = int.Parse(InvoiceDate.Substring(5));
                if ((num2 < 1) || (num2 > 12))
                {
                    throw new Exception();
                }
                if ((num3 < 1) || (num3 > 0x1f))
                {
                    throw new Exception();
                }
            }
            catch (Exception)
            {
                throw new Exception("Invaild InvoiceDate: " + InvoiceDate);
            }
            if (string.IsNullOrEmpty(InvoiceTime))
            {
                throw new Exception("Invaild InvoiceTime: " + InvoiceTime);
            }
            if (string.IsNullOrEmpty(RandomNumber) || (RandomNumber.Length != 4))
            {
                throw new Exception("Invaild RandomNumber: " + RandomNumber);
            }
            if (SalesAmount < 0M)
            {
                throw new Exception("Invaild SalesAmount: " + SalesAmount);
            }
            if (TotalAmount < 0M)
            {
                throw new Exception("Invaild TotalAmount: " + TotalAmount);
            }
            if (string.IsNullOrEmpty(BuyerIdentifier) || (BuyerIdentifier.Length != 8))
            {
                throw new Exception("Invaild BuyerIdentifier: " + BuyerIdentifier);
            }
            if (string.IsNullOrEmpty(RepresentIdentifier))
            {
                throw new Exception("Invaild RepresentIdentifier: " + RepresentIdentifier);
            }
            if (string.IsNullOrEmpty(SellerIdentifier) || (SellerIdentifier.Length != 8))
            {
                throw new Exception("Invaild SellerIdentifier: " + SellerIdentifier);
            }
            if (string.IsNullOrEmpty(BusinessIdentifier))
            {
                throw new Exception("Invaild BusinessIdentifier: " + BusinessIdentifier);
            }
            if ((productArray == null) || (productArray.Length == 0))
            {
                throw new Exception("Invaild ProductArray");
            }
            if (string.IsNullOrEmpty(AESKey))
            {
                throw new Exception("Invaild AESKey");
            }
        }
        /// <summary>
        /// 產生發票左邊QR碼
        /// </summary>
        /// <param name="InvoiceNumber">發票字軌號碼共 10 碼</param>
        /// <param name="InvoiceDate">發票開立年月日(中華民國年份月份日期)共 7 碼</param>
        /// <param name="InvoiceTime">發票開立時間 (24 小時制) 共 6 碼</param>
        /// <param name="RandomNumber">4碼隨機碼</param>
        /// <param name="SalesAmount">以整數方式載入銷售額 (未稅),若無法分離稅項則記載為0</param>
        /// <param name="TaxAmount">以整數方式載入稅額,若無法分離稅項則記載為0</param>
        /// <param name="TotalAmount">整數方式載入總計金額(含稅)</param>
        /// <param name="BuyerIdentifier">買受人統一編號,若買受人為一般消費者,請填入 00000000 8位字串</param>
        /// <param name="RepresentIdentifier">代表店統一編號,電子發票證明聯二維條碼規格已不使用代表店,請填入00000000 8位字串</param>
        /// <param name="SellerIdentifier">銷售店統一編號</param>
        /// <param name="BusinessIdentifier">總機構統一編號,如無總機構請填入銷售店統一編號</param>
        /// <param name="productArray">單項商品資訊</param>
        /// <param name="AESKey">加解密金鑰(QR種子密碼)</param>
        /// <returns></returns>

        public string QRCodeINV(string InvoiceNumber,
            string InvoiceDate,
            string InvoiceTime,
            string RandomNumber,
            decimal SalesAmount,
            decimal TaxAmount,
            decimal TotalAmount,
            string BuyerIdentifier,
            string RepresentIdentifier,
            string SellerIdentifier,
            string BusinessIdentifier,
            string[][] productArray,
            string AESKey)
        {
            try
            {
                this.inputValidate(InvoiceNumber,
                    InvoiceDate,
                    InvoiceTime,
                    RandomNumber,
                    SalesAmount,
                    TaxAmount,
                    TotalAmount,
                    BuyerIdentifier,
                    RepresentIdentifier,
                    SellerIdentifier,
                    BusinessIdentifier,
                    productArray,
                    AESKey);
            }
            catch (Exception exception)
            {
                throw exception;
            }
            return ((InvoiceNumber +
                InvoiceDate +
                RandomNumber +
                Convert.ToInt32(SalesAmount).ToString("x8") +
                Convert.ToInt32(TotalAmount).ToString("x8") +
                BuyerIdentifier + SellerIdentifier) +
                this.AESEncrypt(InvoiceNumber + RandomNumber, AESKey).PadRight(0x18));

    }
    }
}




留言

Snowmeow寫道…
請問這個程式碼財政部網站有source code檔案下載嗎?
Snowmeow寫道…
IV = Convert.FromBase64String("Dt8lyToo17X/XkXaQvihuA==")
這個是固定寫死的嗎?
WILDOX寫道…
Re: Snowmeow <2159789832062737094>

這是向財政部索取『加解密API』裡面有包含的 .NET 檔案,但是目前財政部網站好像看不到,您可以試著向財政部負責人員索取連結看看
WILDOX寫道…
Re: Snowmeow <9054744555897971590>

是的,這是寫死的,這是AES加密用的vectory值(如果你自己要寫AES加密就要用到),建議直接引入『加解密API』裡面包含的DLL就有此加解密方法可用,省得自己寫
Snowmeow寫道…
請問自己包這個DLL,非得用財政部的NAMESPACE嗎?namespace tw.gov.nat.einvoice.qrutil
Snowmeow寫道…
請教您的這篇文章的整包程式(財政部提供的範例程式),是完全可以WORK的嗎?
有沒有甚麼需要注意的地方?
Snowmeow寫道…
請問public string AESEncrypt(string plainText, string AESKey)
其中傳入的第二個參數 AESKey是32碼金鑰 嗎?
Snowmeow寫道…
不好意思,我再問清楚一些,您說這段程式是寫死的:
IV = Convert.FromBase64String("Dt8lyToo17X/XkXaQvihuA==")
所以您貼的這段程式碼,我用在統一發票QR Code,是可以直接照copy使用嗎?
應該說整個dll可以正常用來電子發票的QR code加密使用,對吧?
WILDOX寫道…
Re: Snowmeow <8313403093637410651>

不,自己包的話當然可以改,只是將來財政部如果有更新這段程式碼,下次你在包的時候就要記得改
WILDOX寫道…
Re: Snowmeow <4350709400381603621>

這個是可以WORK的沒有問題,實際上使用時我不會自己打包這段程式碼,而是直接使用財政部提供的DLL檔,如果你使用財政部的DLL檔案,就必須使用它原本的namespace了(使用using引入)
WILDOX寫道…
Re: Snowmeow <1180734487047186389>

是的,這個Key就是32碼金鑰,它的來源是拿你在財政部電子發票平台設定的金鑰(非32碼)丟給它提供的工具genkey.bat去產生32碼金鑰
WILDOX寫道…
Re: Snowmeow <1205635833746668929>

這個IV值是固定的,當你做AES加密時會需要3個東西,分別是來源字串(Source)、金鑰(KEY)、向量(IV),但一般不會用到IV值的設定,因此財政部才把它固定寫死,當然就是全省統一了,這段程式碼片段是我用來學習使用的,為了避免將來財政部更新加密規則或IV值,所以我直接使用它的DLL,這樣以後有更新我只要更換DLL就好,不需要重寫程式碼或是重新編譯程式。
Unknown寫道…
本公司開發了,電子發票 TurnKey SDK DLL 開發套件,讓系統開發商
很容易的就能使用 TurnKey, 而且用戶端不用安裝 SQL, 並提供
"自行檢測V4.4"工具, 讓使用者很簡單的依照指示,就能完成檢測,
並取得上線通行碼, 正常情形15個工作天,即可完成.

此 .NET SDK DLL 並包含電子發票證明聯 5.7*9 熱感紙列印.

宜普科技 凌培軍 0927-217786

這個網誌中的熱門文章

【研究】列印的條碼為什麼很難刷(掃描)

C# 使用 Process.Start 執行外部程式

統一發票列印小程式