crypto.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright (C) 2015 The Syncthing Authors.
  2. // Copyright (C) 2022 Ettore Di Giacinto
  3. //
  4. // This Source Code Form is subject to the terms of the Mozilla Public
  5. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  6. // You can obtain one at https://mozilla.org/MPL/2.0/.
  7. // Package signature provides simple methods to create and verify signatures
  8. // in PEM format.
  9. // Extracted https://github.com/syncthing/syncthing/blob/main/lib/signature/signature.go and adapted to encode directly into base64
  10. package ecdsa
  11. import (
  12. "crypto/ecdsa"
  13. "crypto/elliptic"
  14. "crypto/rand"
  15. "crypto/sha256"
  16. "crypto/x509"
  17. "encoding/asn1"
  18. "encoding/base64"
  19. "encoding/pem"
  20. "errors"
  21. "fmt"
  22. "io"
  23. "math/big"
  24. )
  25. // GenerateKeys returns a new key pair, with the private and public key
  26. // encoded in PEM format.
  27. func GenerateKeys() (privKey []byte, pubKey []byte, err error) {
  28. // Generate a new key pair
  29. key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
  30. if err != nil {
  31. return nil, nil, err
  32. }
  33. // Marshal the private key
  34. bs, err := x509.MarshalECPrivateKey(key)
  35. if err != nil {
  36. return nil, nil, err
  37. }
  38. // Encode it in PEM format
  39. privKey = pem.EncodeToMemory(&pem.Block{
  40. Type: "EC PRIVATE KEY",
  41. Bytes: bs,
  42. })
  43. // Marshal the public key
  44. bs, err = x509.MarshalPKIXPublicKey(key.Public())
  45. if err != nil {
  46. return nil, nil, err
  47. }
  48. // Encode it in PEM format
  49. pubKey = pem.EncodeToMemory(&pem.Block{
  50. Type: "EC PUBLIC KEY",
  51. Bytes: bs,
  52. })
  53. privKey = []byte(base64.URLEncoding.EncodeToString(privKey))
  54. pubKey = []byte(base64.URLEncoding.EncodeToString(pubKey))
  55. return
  56. }
  57. // Sign computes the hash of data and signs it with the private key, returning
  58. // a signature in PEM format.
  59. func sign(privKeyPEM []byte, data io.Reader) ([]byte, error) {
  60. // Parse the private key
  61. key, err := loadPrivateKey(privKeyPEM)
  62. if err != nil {
  63. return nil, err
  64. }
  65. // Hash the reader data
  66. hash, err := hashReader(data)
  67. if err != nil {
  68. return nil, err
  69. }
  70. // Sign the hash
  71. r, s, err := ecdsa.Sign(rand.Reader, key, hash)
  72. if err != nil {
  73. return nil, err
  74. }
  75. // Marshal the signature using ASN.1
  76. sig, err := marshalSignature(r, s)
  77. if err != nil {
  78. return nil, err
  79. }
  80. // Encode it in a PEM block
  81. bs := pem.EncodeToMemory(&pem.Block{
  82. Type: "SIGNATURE",
  83. Bytes: sig,
  84. })
  85. return []byte(base64.URLEncoding.EncodeToString(bs)), nil
  86. }
  87. // Verify computes the hash of data and compares it to the signature using the
  88. // given public key. Returns nil if the signature is correct.
  89. func verify(pubKeyPEM []byte, signature []byte, data io.Reader) error {
  90. // Parse the public key
  91. key, err := loadPublicKey(pubKeyPEM)
  92. if err != nil {
  93. return err
  94. }
  95. bsDec, err := base64.URLEncoding.DecodeString(string(signature))
  96. if err != nil {
  97. return err
  98. }
  99. // Parse the signature
  100. block, _ := pem.Decode(bsDec)
  101. r, s, err := unmarshalSignature(block.Bytes)
  102. if err != nil {
  103. return err
  104. }
  105. // Compute the hash of the data
  106. hash, err := hashReader(data)
  107. if err != nil {
  108. return err
  109. }
  110. // Verify the signature
  111. if !ecdsa.Verify(key, hash, r, s) {
  112. return errors.New("incorrect signature")
  113. }
  114. return nil
  115. }
  116. // hashReader returns the SHA256 hash of the reader
  117. func hashReader(r io.Reader) ([]byte, error) {
  118. h := sha256.New()
  119. if _, err := io.Copy(h, r); err != nil {
  120. return nil, err
  121. }
  122. hash := []byte(fmt.Sprintf("%x", h.Sum(nil)))
  123. return hash, nil
  124. }
  125. // loadPrivateKey returns the ECDSA private key structure for the given PEM
  126. // data.
  127. func loadPrivateKey(bs []byte) (*ecdsa.PrivateKey, error) {
  128. bDecoded, err := base64.URLEncoding.DecodeString(string(bs))
  129. if err != nil {
  130. return nil, err
  131. }
  132. block, _ := pem.Decode([]byte(bDecoded))
  133. return x509.ParseECPrivateKey(block.Bytes)
  134. }
  135. // loadPublicKey returns the ECDSA public key structure for the given PEM
  136. // data.
  137. func loadPublicKey(bs []byte) (*ecdsa.PublicKey, error) {
  138. bDecoded := []byte{}
  139. bDecoded, err := base64.URLEncoding.DecodeString(string(bs))
  140. if err != nil {
  141. return nil, err
  142. }
  143. // Decode and parse the public key PEM block
  144. block, _ := pem.Decode(bDecoded)
  145. intf, err := x509.ParsePKIXPublicKey(block.Bytes)
  146. if err != nil {
  147. return nil, err
  148. }
  149. // It should be an ECDSA public key
  150. pk, ok := intf.(*ecdsa.PublicKey)
  151. if !ok {
  152. return nil, errors.New("unsupported public key format")
  153. }
  154. return pk, nil
  155. }
  156. // A wrapper around the signature integers so that we can marshal and
  157. // unmarshal them.
  158. type signature struct {
  159. R, S *big.Int
  160. }
  161. // marshalSignature returns ASN.1 encoded bytes for the given integers,
  162. // suitable for PEM encoding.
  163. func marshalSignature(r, s *big.Int) ([]byte, error) {
  164. sig := signature{
  165. R: r,
  166. S: s,
  167. }
  168. bs, err := asn1.Marshal(sig)
  169. if err != nil {
  170. return nil, err
  171. }
  172. return bs, nil
  173. }
  174. // unmarshalSignature returns the R and S integers from the given ASN.1
  175. // encoded signature.
  176. func unmarshalSignature(sig []byte) (r *big.Int, s *big.Int, err error) {
  177. var ts signature
  178. _, err = asn1.Unmarshal(sig, &ts)
  179. if err != nil {
  180. return nil, nil, err
  181. }
  182. return ts.R, ts.S, nil
  183. }