You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

91 lines
3.4 KiB

  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package sign signs small messages using public-key cryptography.
  5. //
  6. // Sign uses Ed25519 to sign messages. The length of messages is not hidden.
  7. // Messages should be small because:
  8. // 1. The whole message needs to be held in memory to be processed.
  9. // 2. Using large messages pressures implementations on small machines to process
  10. // plaintext without verifying the signature. This is very dangerous, and this API
  11. // discourages it, but a protocol that uses excessive message sizes might present
  12. // some implementations with no other choice.
  13. // 3. Performance may be improved by working with messages that fit into data caches.
  14. // Thus large amounts of data should be chunked so that each message is small.
  15. //
  16. // This package is not interoperable with the current release of NaCl
  17. // (https://nacl.cr.yp.to/sign.html), which does not support Ed25519 yet. However,
  18. // it is compatible with the NaCl fork libsodium (https://www.libsodium.org), as well
  19. // as TweetNaCl (https://tweetnacl.cr.yp.to/).
  20. package sign
  21. import (
  22. "io"
  23. "golang.org/x/crypto/ed25519"
  24. "golang.org/x/crypto/internal/subtle"
  25. )
  26. // Overhead is the number of bytes of overhead when signing a message.
  27. const Overhead = 64
  28. // GenerateKey generates a new public/private key pair suitable for use with
  29. // Sign and Open.
  30. func GenerateKey(rand io.Reader) (publicKey *[32]byte, privateKey *[64]byte, err error) {
  31. pub, priv, err := ed25519.GenerateKey(rand)
  32. if err != nil {
  33. return nil, nil, err
  34. }
  35. publicKey, privateKey = new([32]byte), new([64]byte)
  36. copy((*publicKey)[:], pub)
  37. copy((*privateKey)[:], priv)
  38. return publicKey, privateKey, nil
  39. }
  40. // Sign appends a signed copy of message to out, which will be Overhead bytes
  41. // longer than the original and must not overlap it.
  42. func Sign(out, message []byte, privateKey *[64]byte) []byte {
  43. sig := ed25519.Sign(ed25519.PrivateKey((*privateKey)[:]), message)
  44. ret, out := sliceForAppend(out, Overhead+len(message))
  45. if subtle.AnyOverlap(out, message) {
  46. panic("nacl: invalid buffer overlap")
  47. }
  48. copy(out, sig)
  49. copy(out[Overhead:], message)
  50. return ret
  51. }
  52. // Open verifies a signed message produced by Sign and appends the message to
  53. // out, which must not overlap the signed message. The output will be Overhead
  54. // bytes smaller than the signed message.
  55. func Open(out, signedMessage []byte, publicKey *[32]byte) ([]byte, bool) {
  56. if len(signedMessage) < Overhead {
  57. return nil, false
  58. }
  59. if !ed25519.Verify(ed25519.PublicKey((*publicKey)[:]), signedMessage[Overhead:], signedMessage[:Overhead]) {
  60. return nil, false
  61. }
  62. ret, out := sliceForAppend(out, len(signedMessage)-Overhead)
  63. if subtle.AnyOverlap(out, signedMessage) {
  64. panic("nacl: invalid buffer overlap")
  65. }
  66. copy(out, signedMessage[Overhead:])
  67. return ret, true
  68. }
  69. // sliceForAppend takes a slice and a requested number of bytes. It returns a
  70. // slice with the contents of the given slice followed by that many bytes and a
  71. // second slice that aliases into it and contains only the extra bytes. If the
  72. // original slice has sufficient capacity then no allocation is performed.
  73. func sliceForAppend(in []byte, n int) (head, tail []byte) {
  74. if total := len(in) + n; cap(in) >= total {
  75. head = in[:total]
  76. } else {
  77. head = make([]byte, total)
  78. copy(head, in)
  79. }
  80. tail = head[len(in):]
  81. return
  82. }