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