2019年4月14日 星期日

用指令來玩轉數位簽章

目錄

認識數位簽章

數位簽章

數位簽章(英語:Digital Signature)是一種用於鑑別數位信息的方法。一套數位簽章通常定義兩種互補的運算,一個用於簽名,另一個用於驗證,電子簽章用以辨識及確認電子文件簽署人身分電子文件的真偽。

數位簽章流程圖

簽章流程

  1. 將資料(Data)通過雜湊演算法獲得一個雜湊值(Hash)有時又稱作指紋(fingerprint)
  2. 使用對稱式密鑰中的私鑰(Private Key)對雜湊值(Hash)進行加簽得到簽章(Signature)
  3. 將簽章(Signature)、憑證(Certificate)作為資料(Data)附件稱為數位簽章資料(Digitally signed data)

驗證流程

  1. 數位簽章資料分成簽章和資料
    • 使用對稱式密鑰中的公鑰(Public Key)對進行解簽取得簽章中的雜湊值(Hash)
    • 將資料(Data)通過雜湊演算法獲得一個雜湊值(Hash)
  2. 比對 1. 所產生的兩個雜湊值(Hash)是否相同,相同則代表內容正確驗證通過

補充重點

  1. 簽章流程中的憑證(Certificate)有可能以其他方式釋放出來不一定以附件形式夾帶
  2. 驗證流程中的公鑰來自於憑證(Certificate)
  3. 圖中並未詳細提到雜湊演算法,以 openssl 實際運作為例
    1. 雜湊演算法由簽章者於簽章時決定,並且將雜湊演算方式放入簽章(Signature)中
    2. 簽章內容包含雜湊值(Hash)及雜湊演算方式,兩種資料使用 asn1 格式來儲存
    3. 使用者在解簽後會取得雜湊演算方式,因此知道要將資料(Data)通過哪種方式計算出雜湊值(Hash)

用指令來玩數位簽章

測試環境

itemversion
OSmacOS Sierra
opensslOpenSSL 1.0.2o.

製作私鑰及憑證

  1. 製作私鑰
    Bash
    $ openssl genrsa -out my.key 2048
    Generating RSA private key, 2048 bit long modulus
    ................................................................+++
    ..............+++
    e is 65537 (0x10001)
    
  2. 建立憑證
    Bash
    $ openssl req -x509 -new -nodes -key my.key -sha256 -days 3650 -out my.crt
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [AU]: TW
    State or Province Name (full name) [Some-State]: Taipei
    Locality Name (eg, city) []:
    Organization Name (eg, company) [Internet Widgits Pty Ltd]: Cookie's Lab
    Organizational Unit Name (eg, section) []:
    Common Name (e.g. server FQDN or YOUR name) []: CookieTsai
    Email Address []:
    
  3. 查看私鑰
    Bash
    $ openssl rsa -in my.key -text -noout
    Private-Key: (2048 bit)
    modulus:
        00:c8:32:fd:5d:66:9e:8f:34:d4:e5:1c:79:69:3d:
        53:47:96:92:47:77:7b:07:48:bd:01:dc:f8:be:49:
        a5:3c:18:88:f2:6f:bc:83:43:9a:d1:9f:33:54:bb:
        e1:db:8e:3f:f7:c2:7f:64:51:88:0a:38:4c:cf:73:
        d9:34:c0:3c:a0:a4:bd:11:bf:81:60:07:3f:41:85:
        81:c4:1a:7e:cf:20:90:ea:60:7d:c1:52:c1:a7:8d:
        6a:4c:9c:73:de:6b:3d:6d:bc:63:a0:7a:99:29:9c:
        c9:a2:c0:b5:18:68:d3:f8:30:fc:42:91:be:a0:26:
        74:b6:9a:e9:20:b4:8c:7b:c8:04:06:7d:7f:1b:14:
        7a:d6:0e:62:7f:9c:9f:12:fc:a3:f6:63:5c:cd:c1:
        2a:d7:59:e7:47:8c:37:d0:f7:80:76:7a:cf:ce:3a:
        6e:05:04:bd:24:46:e5:06:a9:6c:cd:15:8d:7f:3b:
        a0:f2:a1:44:7c:a9:40:54:4b:cc:97:fd:8c:cb:18:
        6c:bf:50:a0:b8:32:68:9d:29:78:17:29:53:e5:a1:
        74:b6:34:20:49:16:a6:f4:a2:a5:80:89:f4:36:b3:
        52:25:64:e8:59:b0:f5:a3:91:f2:c2:a1:da:6c:5d:
        ea:ed:90:75:bd:bd:ae:c6:8a:70:61:5b:a1:6c:14:
        27:3f
    publicExponent: 65537 (0x10001)
    privateExponent:
        13:f1:c8:7e:02:98:2f:4a:23:1f:84:1b:b0:59:54:
        af:a0:17:88:99:25:9f:8f:26:8d:45:f7:5d:f5:b6:
        49:6b:64:51:4a:c2:6c:0d:53:22:29:0b:13:18:f8:
        a2:47:e4:a5:89:31:e9:cb:99:92:f3:12:eb:e3:ed:
        b2:ac:a8:1d:94:eb:e5:15:c0:0c:d2:0c:02:3a:0b:
        b8:7e:af:3d:71:50:1e:99:68:4d:d7:31:c5:c0:77:
        e3:93:fe:93:1c:f9:ec:b1:c4:f7:1a:df:a1:5e:a6:
        53:d9:80:f1:22:98:63:74:75:dd:27:e9:e6:c8:8d:
        fe:17:26:bc:84:60:2e:80:8c:92:9d:7e:01:e2:e5:
        92:df:3d:fe:41:52:ac:db:3c:ad:bb:df:1d:76:86:
        53:fb:8b:65:1f:39:cd:dc:59:e1:f6:ac:41:eb:9e:
        bd:d2:7d:e5:55:94:c6:b7:a3:0e:46:4f:67:b2:f4:
        be:a7:50:bf:da:20:0d:63:c1:f3:70:da:4b:e3:ae:
        a9:41:ca:51:66:a5:71:de:c3:89:98:fa:ba:7d:2d:
        ee:20:f3:14:f8:08:69:d1:f6:ed:28:cd:1e:e1:45:
        e3:bd:c7:fa:9b:53:71:9b:5d:69:34:e4:1c:7c:75:
        cc:d4:da:d1:2e:86:7f:79:96:a1:fb:e7:c0:e6:41:
        f1
    prime1:
        00:e2:82:a1:ec:5e:df:b8:e2:ef:5b:b8:01:3e:12:
        65:ea:2c:00:c2:6d:2b:d4:34:99:b8:7a:f9:f0:58:
        b6:05:f8:7c:1b:55:9e:6a:c2:6b:5a:2d:a2:61:77:
        0b:e3:f2:97:58:09:95:e1:4a:44:01:c0:d4:6a:49:
        7a:79:1e:0c:4e:a2:82:1c:3a:25:71:47:7d:4d:d3:
        b6:dd:33:55:b5:3d:16:f7:35:4d:46:f9:7f:18:a0:
        32:35:6d:fc:32:3c:f0:7b:4f:8a:9b:d8:35:58:b0:
        1d:30:3b:d7:9c:e7:8e:d4:00:36:ee:d4:4e:46:75:
        3c:a7:be:b9:b5:0d:b4:1a:29
    prime2:
        00:e2:43:6f:04:31:72:60:8f:d9:79:4a:ac:29:d3:
        c6:8a:63:1f:df:c3:ea:64:74:f5:74:36:9b:f7:84:
        8f:c0:45:e7:3f:b8:7c:9e:79:53:a4:c3:9c:b4:f4:
        17:f4:c3:12:0a:b8:7c:5d:73:e6:3e:55:ee:2b:57:
        a3:0b:98:e2:f1:0b:10:28:18:ee:a9:88:1d:f5:16:
        0e:22:44:4d:28:30:03:97:ae:fa:53:ec:3a:ed:7f:
        5b:e6:df:79:65:9c:30:fc:fc:5e:9a:70:7e:3c:f7:
        e4:f0:24:e9:2a:0e:55:87:40:5e:c1:73:52:7b:b9:
        f3:7a:c8:18:8a:fa:be:33:27
    exponent1:
        00:d2:84:b2:d5:aa:bf:a7:68:53:2a:1d:74:1a:2a:
        a3:49:e7:27:b5:8c:1d:86:16:75:20:3e:3b:79:a4:
        19:58:a7:3f:41:70:6b:d1:b1:6c:70:dd:a4:e3:8c:
        ef:22:26:5f:7e:d5:39:d5:af:5e:51:7a:d4:71:0c:
        65:a5:97:c5:bc:77:d1:11:47:01:71:ad:0d:ca:7d:
        90:a1:39:8a:d8:ed:34:21:02:0b:16:81:e0:1c:15:
        17:55:0d:29:ad:cf:71:7a:49:cc:fb:57:11:0d:a2:
        71:1e:59:1f:e5:96:58:ea:b4:60:59:cc:3c:0b:c3:
        fe:61:b1:23:8c:20:76:59:31
    exponent2:
        45:a3:b1:a8:9d:bb:71:62:f4:f1:72:fd:38:46:79:
        26:20:ca:2f:a9:f2:1b:87:30:00:db:c9:f7:4d:b2:
        9c:e0:27:03:a2:b9:a0:61:01:50:85:f0:56:75:86:
        66:0c:20:22:72:93:bc:83:ae:8a:e3:11:d1:ff:40:
        2c:92:9a:ce:cb:b3:e6:53:7e:29:69:be:a6:af:6a:
        1c:3b:df:6f:8e:0f:9d:00:fb:05:17:81:2f:95:f2:
        68:45:c1:ec:77:3d:50:b0:30:41:e2:7b:c8:32:18:
        21:9d:8a:b2:2a:05:43:02:99:e7:7a:a2:19:78:ab:
        2a:d0:29:55:a5:45:23:23
    coefficient:
        45:03:43:0d:28:3c:d3:68:3b:64:be:83:9b:67:e5:
        d3:df:0d:b1:2a:73:2d:43:e3:29:fc:1d:0d:47:b9:
        2e:bb:e9:49:e9:4b:bd:ce:48:7d:84:7f:85:24:ca:
        43:f3:0e:b8:dd:d1:e4:92:ff:24:7d:7a:eb:af:6c:
        df:30:99:67:cd:86:50:c3:9c:b4:5a:ee:98:b2:d0:
        a2:ce:bc:53:8d:b4:5e:2b:f0:7e:9a:66:09:e8:5f:
        87:cc:c5:e4:67:5e:a3:ba:89:3a:eb:84:52:48:ad:
        03:73:1f:0a:be:56:1e:0d:16:3a:db:86:c8:0c:e8:
        1a:e7:70:95:de:01:98:14
    
  4. 查看憑證
    Bash
    $ openssl x509 -in my.crt -text -noout
    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number:
                98:3c:cd:50:90:ed:b7:74
        Signature Algorithm: sha256WithRSAEncryption
            Issuer: C=TW, ST=Taipei, O=Cookie's Lab, CN=CookieTsai
            Validity
                Not Before: Apr 12 07:04:18 2019 GMT
                Not After : Apr  9 07:04:18 2029 GMT
            Subject: C=TW, ST=Taipei, O=Cookie's Lab, CN=CookieTsai
            Subject Public Key Info:
                Public Key Algorithm: rsaEncryption
                    Public-Key: (2048 bit)
                    Modulus:
                        00:c8:32:fd:5d:66:9e:8f:34:d4:e5:1c:79:69:3d:
                        53:47:96:92:47:77:7b:07:48:bd:01:dc:f8:be:49:
                        a5:3c:18:88:f2:6f:bc:83:43:9a:d1:9f:33:54:bb:
                        e1:db:8e:3f:f7:c2:7f:64:51:88:0a:38:4c:cf:73:
                        d9:34:c0:3c:a0:a4:bd:11:bf:81:60:07:3f:41:85:
                        81:c4:1a:7e:cf:20:90:ea:60:7d:c1:52:c1:a7:8d:
                        6a:4c:9c:73:de:6b:3d:6d:bc:63:a0:7a:99:29:9c:
                        c9:a2:c0:b5:18:68:d3:f8:30:fc:42:91:be:a0:26:
                        74:b6:9a:e9:20:b4:8c:7b:c8:04:06:7d:7f:1b:14:
                        7a:d6:0e:62:7f:9c:9f:12:fc:a3:f6:63:5c:cd:c1:
                        2a:d7:59:e7:47:8c:37:d0:f7:80:76:7a:cf:ce:3a:
                        6e:05:04:bd:24:46:e5:06:a9:6c:cd:15:8d:7f:3b:
                        a0:f2:a1:44:7c:a9:40:54:4b:cc:97:fd:8c:cb:18:
                        6c:bf:50:a0:b8:32:68:9d:29:78:17:29:53:e5:a1:
                        74:b6:34:20:49:16:a6:f4:a2:a5:80:89:f4:36:b3:
                        52:25:64:e8:59:b0:f5:a3:91:f2:c2:a1:da:6c:5d:
                        ea:ed:90:75:bd:bd:ae:c6:8a:70:61:5b:a1:6c:14:
                        27:3f
                    Exponent: 65537 (0x10001)
            X509v3 extensions:
                X509v3 Subject Key Identifier:
                    87:6E:65:DF:0C:06:A4:8C:87:50:05:1A:15:C3:62:77:6E:D6:09:23
                X509v3 Authority Key Identifier:
                    keyid:87:6E:65:DF:0C:06:A4:8C:87:50:05:1A:15:C3:62:77:6E:D6:09:23
    
                X509v3 Basic Constraints:
                    CA:TRUE
        Signature Algorithm: sha256WithRSAEncryption
             c0:d8:49:32:0a:0d:d3:5d:4a:05:9c:3d:5c:6f:ee:3d:cb:2b:
             1e:21:69:34:3a:4b:58:dc:64:bc:36:8f:b4:ac:aa:ee:38:e1:
             b4:51:eb:aa:b3:24:aa:f4:86:a9:6d:a6:59:0f:87:1a:07:50:
             d6:b1:40:fe:87:12:8d:eb:96:ac:89:79:da:ba:9d:2c:00:d1:
             d6:66:50:60:1a:56:06:95:1f:65:b4:28:32:3a:eb:47:5b:98:
             bd:f1:8f:91:44:a9:f8:94:bf:61:c4:40:c3:67:94:c8:5e:46:
             41:ca:ca:a1:b8:4b:be:ad:43:db:4d:01:1d:f5:2a:07:b4:01:
             16:18:9b:9a:5d:35:b4:0e:d4:7f:b3:f3:46:47:7c:4e:4c:e4:
             35:02:b2:65:ba:21:88:c9:59:28:1d:17:60:71:18:18:24:a8:
             88:b8:83:59:3e:98:cf:76:da:a2:be:78:21:0f:a8:85:03:e6:
             97:02:68:33:82:43:6c:b7:af:a3:d7:2e:7a:75:55:b4:75:d6:
             2b:7a:4d:32:78:73:b4:49:fa:64:fb:8a:5f:a0:70:5e:f6:80:
             27:92:2d:dc:f0:22:c8:9f:e7:f8:b5:fe:f7:c4:9d:fd:4f:0c:
             b8:12:89:0e:7e:a6:0b:0b:83:fb:65:59:1b:be:2a:26:29:35:
             9d:55:7f:59
    

補充重點

  1. 私鑰及憑證中都包含了公鑰完整的資訊,所以在應用上會看到例子是拿私鑰或憑證去解開加簽的資料
  2. 上方憑證是一個自簽憑證,在憑證內容中最下方的 Hex 內容就是簽章,是可以被驗證的方法如下:
    1. 取出憑證中數位簽章內容,並以私鑰中的公鑰進行解簽,最後將 DER 的資料以 ASN1 的結構呈現
      Bash
      $ openssl x509 -in my.crt -text -noout -certopt ca_default -certopt no_validity \
      -certopt no_serial -certopt no_subject -certopt no_extensions -certopt no_signame | \
      grep -v 'Signature Algorithm' | tr -d '[:space:]:' | xxd -r -p | \
      openssl rsautl -verify -inkey my.key -asn1parse
          0:d=0  hl=2 l=  49 cons: SEQUENCE
          2:d=1  hl=2 l=  13 cons:  SEQUENCE
          4:d=2  hl=2 l=   9 prim:   OBJECT            :sha256
         15:d=2  hl=2 l=   0 prim:   NULL
         17:d=1  hl=2 l=  32 prim:  OCTET STRING
            0000 - b5 cb da 6d 3e 8d 0b 1f-47 a9 f0 50 e7 ce 0c 59   ...m>...G..P...Y
            0010 - 5b a3 a9 71 a2 33 f6 e0-09 4b d9 2f 71 3d 3a 9b   [..q.3...K./q=:.
      
    2. 取出憑證內容中的 tbsCertificate 資料使用簽章中提到的 sha256 進行雜湊演算
      Certificate  ::=  SEQUENCE  {
           tbsCertificate       TBSCertificate, // TBS 意思是 To Be Sign
           signatureAlgorithm   AlgorithmIdentifier,
           signatureValue       BIT STRING  }
      註解:Certificate 中的 tbsCertificate 是憑證中被加簽的內容
      1. 算出憑證中 tbsCertificate 的位置
      Bash
      $ OFFSET=$(openssl asn1parse -in my.crt | awk 'FNR==2{print $0}' | cut -d":" -f1)
      1. 將 tbsCertificate 從憑證中取出並存放入 tbsCertificate.der 中
      Bash
      $ openssl asn1parse -in my.crt -strparse $OFFSET -out tbsCertificate.der -noout
      1. 使用 sha256 進行雜湊演算
      Bash
      $ openssl dgst -sha256 tbsCertificate.der
      SHA256(tbsCertificate.der)= b5cbda6d3e8d0b1f47a9f050e7ce0c595ba3a971a233f6e0094bd92f713d3a9b
      
    3. 對比兩份數據會發現 Hex 相同所以驗證通過
      第一份
          0:d=0  hl=2 l=  49 cons: SEQUENCE
          2:d=1  hl=2 l=  13 cons:  SEQUENCE
          4:d=2  hl=2 l=   9 prim:   OBJECT            :sha256
         15:d=2  hl=2 l=   0 prim:   NULL
         17:d=1  hl=2 l=  32 prim:  OCTET STRING
            0000 - b5 cb da 6d 3e 8d 0b 1f-47 a9 f0 50 e7 ce 0c 59   ...m>...G..P...Y
            0010 - 5b a3 a9 71 a2 33 f6 e0-09 4b d9 2f 71 3d 3a 9b   [..q.3...K./q=:.
      
      第二份
      SHA256(tbsCertificate.der)= b5cbda6d3e8d0b1f47a9f050e7ce0c595ba3a971a233f6e0094bd92f713d3a9b
      
      註解:Hex Code 的部分又可以稱作『指紋(fingerprint)』

製作數位簽章

在開始製作數位簽章前,說一下關於 openssl 裡面加簽方式分為兩類。差異在於有沒有 Hash + ASN1,其中有經過 Hash 的可用 openssl dgst 來製作,沒有經過 Hash 的則可以用 openssl rsautl。這並不是 openssl 唯二的兩種加簽指令,有興趣的可以再多研究,沒意外應該就是屬於這兩類其一。

第一種:製作有 hash 的加簽

  • ASN1(Hash function + (Data Hash)) + RSA 私鑰加簽 => 數位簽章
    加簽 + Base64
    Bash
    $ echo "Hello World" | openssl dgst -sha256 -sign my.key | openssl enc -base64
    jaqTRJS/FdFn6E1IwEFQTjfotBGJh9D+axqwkqdfxRlhZyUWLPpUb0CdusX2YKjv
    0AyysN2B/Z6YlNs6319Qy7nud7FDrkdZtIpVdalE7L6BJXc6/7L+1J/LcBGGXNMz
    sZiGNpksb1mn0Qd0k5lycqoibF2CPhLuhFdvUgRQ7z3zq132qV2G2kQFrXV+EfPK
    T4d2YdUU1CVKkMSQEJiOCljzaz2VYR6ajIsCiVfvLgOxc4Pcp64ZtdKR/RbUD6+3
    HhFTdOX8yaOoFAWRkKT0K4VxFv5DP3EMIrLiANnc8hcOkJAAfLDEJSXoSczTPVN1
    iOzFjzN0ND4T80oDMGnc/g==
    
    加簽後直接解簽
    Bash
    $ echo "Hello World" | openssl dgst -sha256 -sign my.key | \
    openssl rsautl -verify -inkey my.key -asn1parse
        0:d=0  hl=2 l=  49 cons: SEQUENCE
        2:d=1  hl=2 l=  13 cons:  SEQUENCE
        4:d=2  hl=2 l=   9 prim:   OBJECT            :sha256
       15:d=2  hl=2 l=   0 prim:   NULL
       17:d=1  hl=2 l=  32 prim:  OCTET STRING
          0000 - d2 a8 4f 4b 8b 65 09 37-ec 8f 73 cd 8b e2 c7 4a   ..OK.e.7..s....J
          0010 - dd 5a 91 1b a6 4d f2 74-58 ed 82 29 da 80 4a 26   .Z...M.tX..)..J&
    
    註解:此加簽方式會以 ASN1 + DER 的資料作為被加簽對象

第二種:製作沒有 hash 的加簽

  • Data + RSA 私鑰加簽 => 資料加簽
    加簽 + Base64
    Bash
    $ echo "Hello World" | openssl rsautl -sign -inkey my.key | openssl enc -base64
    wD+bQB0yL5Ks0aj4CviAYVNaHULrdJzg50Remo6h80COiwcUZ0SKRHVQH2TGH+xD
    lyw9TE0tB1a0ec+yqIEkIu7J3wCXMWflFMQdk6Vr0j/OHKAaiBOpvmMyq1xlZLVb
    itFMQVqZYNQKmBvotBXm/TN2fRPiRB/X0QUmS5WsfRRQWssfgFUdKLFs2nXWdUza
    X/pPW3mnL4oTnzdWU0kTCjT36CzfF+5Q7UdySeEUX/TtU8TT1EGez9s3AzfkS+Xe
    nIuj71AkhJs7RfY2LE0p05gkCgZrxFbkJXNqtrQB1MUCw+frkAv+cTz+hfpy2ggA
    3DiKYeAFVRQhLru7YAzS/Q==
    
    加簽後直接解簽
    Bash
    $ echo "Hello World" | openssl rsautl -sign -inkey my.key | \
    openssl rsautl -verify -inkey my.key
    Hello World
    
    註解:此加簽方式須留意加簽資料長度是必須小於鑰匙長度(2048 bit 鑰匙只能加簽小於 256 byte 的資料)

結語

數位簽章的特性使得資料,可以在不安全的環境中傳遞,並且不怕被有心人士擷取,在一些時候這個特性真的非常重要。在我們日常中常接觸到的自然人憑證其實也是使用相同原理在運作,期許這邊文章能幫助更多人認識數加簽的過程以及實際作動。