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