gut libsodium for rewrite
This commit is contained in:
parent
bb890e716b
commit
81a08bb407
1
contrib/backends/nntpchand/.gitignore
vendored
Normal file
1
contrib/backends/nntpchand/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
nntpchand
|
@ -20,10 +20,9 @@ func (fucky *fuckyNacl) Sign() (s Signature) {
|
||||
if h == nil {
|
||||
panic("fuck.hash.Sum == nil")
|
||||
}
|
||||
kp := nacl.LoadSignKey(fucky.k)
|
||||
defer kp.Free()
|
||||
sk := kp.Secret()
|
||||
sig := nacl.CryptoSignFucky(h, sk)
|
||||
|
||||
_, sec := nacl.SeedToKeyPair(fucky.k)
|
||||
sig := nacl.CryptoSignFucky(h, sec)
|
||||
if sig == nil {
|
||||
panic("fucky signer's call to nacl.CryptoSignFucky returned nil")
|
||||
}
|
||||
@ -40,7 +39,7 @@ func (fucky *fuckyNacl) resetState() {
|
||||
func (fucky *fuckyNacl) Verify(sig Signature) (valid bool) {
|
||||
h := fucky.hash.Sum(nil)
|
||||
if h == nil {
|
||||
panic("fuck.hash.Sum == nil")
|
||||
panic("fucky.hash.Sum == nil")
|
||||
}
|
||||
valid = nacl.CryptoVerifyFucky(h, sig, fucky.k)
|
||||
fucky.resetState()
|
||||
@ -66,17 +65,13 @@ func CreateVerifier(pk []byte) Verifer {
|
||||
|
||||
// get the public component given the secret key
|
||||
func ToPublic(sk []byte) (pk []byte) {
|
||||
kp := nacl.LoadSignKey(sk)
|
||||
defer kp.Free()
|
||||
pk = kp.Public()
|
||||
pk, _ = nacl.SeedToKeyPair(sk)
|
||||
return
|
||||
}
|
||||
|
||||
// create a standard keypair
|
||||
func GenKeypair() (pk, sk []byte) {
|
||||
kp := nacl.GenSignKeypair()
|
||||
defer kp.Free()
|
||||
pk = kp.Public()
|
||||
sk = kp.Seed()
|
||||
sk = RandBytes(32)
|
||||
pk, _ = nacl.SeedToKeyPair(sk)
|
||||
return
|
||||
}
|
||||
|
@ -1,95 +0,0 @@
|
||||
package nacl
|
||||
|
||||
// #cgo freebsd CFLAGS: -I/usr/local/include
|
||||
// #cgo freebsd LDFLAGS: -L/usr/local/lib
|
||||
// #cgo LDFLAGS: -lsodium
|
||||
// #include <sodium.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// encrypts a message to a user given their public key is known
|
||||
// returns an encrypted box
|
||||
func CryptoBox(msg, nounce, pk, sk []byte) ([]byte, error) {
|
||||
msgbuff := NewBuffer(msg)
|
||||
defer msgbuff.Free()
|
||||
|
||||
// check sizes
|
||||
if len(pk) != int(C.crypto_box_publickeybytes()) {
|
||||
err := errors.New("len(pk) != crypto_box_publickey_bytes")
|
||||
return nil, err
|
||||
}
|
||||
if len(sk) != int(C.crypto_box_secretkeybytes()) {
|
||||
err := errors.New("len(sk) != crypto_box_secretkey_bytes")
|
||||
return nil, err
|
||||
}
|
||||
if len(nounce) != int(C.crypto_box_macbytes()) {
|
||||
err := errors.New("len(nounce) != crypto_box_macbytes()")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkbuff := NewBuffer(pk)
|
||||
defer pkbuff.Free()
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
nouncebuff := NewBuffer(nounce)
|
||||
defer nouncebuff.Free()
|
||||
|
||||
resultbuff := malloc(msgbuff.size + nouncebuff.size)
|
||||
defer resultbuff.Free()
|
||||
res := C.crypto_box_easy(resultbuff.uchar(), msgbuff.uchar(), C.ulonglong(msgbuff.size), nouncebuff.uchar(), pkbuff.uchar(), skbuff.uchar())
|
||||
if res != 0 {
|
||||
err := errors.New("crypto_box_easy failed")
|
||||
return nil, err
|
||||
}
|
||||
return resultbuff.Bytes(), nil
|
||||
}
|
||||
|
||||
// open an encrypted box
|
||||
func CryptoBoxOpen(box, nounce, sk, pk []byte) ([]byte, error) {
|
||||
boxbuff := NewBuffer(box)
|
||||
defer boxbuff.Free()
|
||||
|
||||
// check sizes
|
||||
if len(pk) != int(C.crypto_box_publickeybytes()) {
|
||||
err := errors.New("len(pk) != crypto_box_publickey_bytes")
|
||||
return nil, err
|
||||
}
|
||||
if len(sk) != int(C.crypto_box_secretkeybytes()) {
|
||||
err := errors.New("len(sk) != crypto_box_secretkey_bytes")
|
||||
return nil, err
|
||||
}
|
||||
if len(nounce) != int(C.crypto_box_macbytes()) {
|
||||
err := errors.New("len(nounce) != crypto_box_macbytes()")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkbuff := NewBuffer(pk)
|
||||
defer pkbuff.Free()
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
nouncebuff := NewBuffer(nounce)
|
||||
defer nouncebuff.Free()
|
||||
resultbuff := malloc(boxbuff.size - nouncebuff.size)
|
||||
defer resultbuff.Free()
|
||||
|
||||
// decrypt
|
||||
res := C.crypto_box_open_easy(resultbuff.uchar(), boxbuff.uchar(), C.ulonglong(boxbuff.size), nouncebuff.uchar(), pkbuff.uchar(), skbuff.uchar())
|
||||
if res != 0 {
|
||||
return nil, errors.New("crypto_box_open_easy failed")
|
||||
}
|
||||
// return result
|
||||
return resultbuff.Bytes(), nil
|
||||
}
|
||||
|
||||
// generate a new nounce
|
||||
func NewBoxNounce() []byte {
|
||||
return RandBytes(NounceLen())
|
||||
}
|
||||
|
||||
// length of a nounce
|
||||
func NounceLen() int {
|
||||
return int(C.crypto_box_macbytes())
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
package nacl
|
||||
|
||||
// #cgo freebsd CFLAGS: -I/usr/local/include
|
||||
// #cgo freebsd LDFLAGS: -L/usr/local/lib
|
||||
// #cgo LDFLAGS: -lsodium
|
||||
// #include <sodium.h>
|
||||
//
|
||||
// unsigned char * deref_uchar(void * ptr) { return (unsigned char*) ptr; }
|
||||
//
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// wrapper arround malloc/free
|
||||
type Buffer struct {
|
||||
ptr unsafe.Pointer
|
||||
length C.int
|
||||
size C.size_t
|
||||
}
|
||||
|
||||
// wrapper arround nacl.malloc
|
||||
func Malloc(size int) *Buffer {
|
||||
if size > 0 {
|
||||
return malloc(C.size_t(size))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// does not check for negatives
|
||||
func malloc(size C.size_t) *Buffer {
|
||||
ptr := C.malloc(size)
|
||||
C.sodium_memzero(ptr, size)
|
||||
buffer := &Buffer{ptr: ptr, size: size, length: C.int(size)}
|
||||
return buffer
|
||||
}
|
||||
|
||||
// create a new buffer copying from a byteslice
|
||||
func NewBuffer(buff []byte) *Buffer {
|
||||
buffer := Malloc(len(buff))
|
||||
if buffer == nil {
|
||||
return nil
|
||||
}
|
||||
if copy(buffer.Data(), buff) != len(buff) {
|
||||
return nil
|
||||
}
|
||||
return buffer
|
||||
}
|
||||
|
||||
func (self *Buffer) uchar() *C.uchar {
|
||||
return C.deref_uchar(self.ptr)
|
||||
}
|
||||
|
||||
func (self *Buffer) Length() int {
|
||||
return int(self.length)
|
||||
}
|
||||
|
||||
// get immutable byte slice
|
||||
func (self *Buffer) Bytes() []byte {
|
||||
buff := make([]byte, self.Length())
|
||||
copy(buff, self.Data())
|
||||
return buff
|
||||
}
|
||||
|
||||
// get underlying byte slice
|
||||
func (self *Buffer) Data() []byte {
|
||||
hdr := reflect.SliceHeader{
|
||||
Data: uintptr(self.ptr),
|
||||
Len: self.Length(),
|
||||
Cap: self.Length(),
|
||||
}
|
||||
return *(*[]byte)(unsafe.Pointer(&hdr))
|
||||
}
|
||||
|
||||
func (self *Buffer) String() string {
|
||||
return hex.EncodeToString(self.Data())
|
||||
}
|
||||
|
||||
// zero out memory and then free
|
||||
func (self *Buffer) Free() {
|
||||
C.sodium_memzero(self.ptr, self.size)
|
||||
C.free(self.ptr)
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package nacl
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"edwards25519"
|
||||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
func CryptoVerifyFucky(h, sig, pk []byte) bool {
|
||||
pub := make(ed25519.PublicKey, ed25519.PublicKeySize)
|
||||
copy(pub, pk)
|
||||
return ed25519.Verify(pub, h, sig)
|
||||
}
|
||||
|
||||
func CryptoSignFucky(hash, sk []byte) []byte {
|
||||
sec := make(ed25519.PrivateKey, ed25519.PrivateKeySize)
|
||||
copy(sec, sk)
|
||||
return ed25519.Sign(sec, hash)
|
||||
}
|
||||
|
||||
func SeedToKeyPair(seed []byte) (pk, sk []byte) {
|
||||
|
||||
h := sha512.Sum512(seed[0:32])
|
||||
sk = h[:]
|
||||
sk[0] &= 248
|
||||
sk[31] &= 63
|
||||
sk[31] |= 64
|
||||
// scalarmult magick shit
|
||||
pk = scalarBaseMult(sk[0:32])
|
||||
copy(sk[0:32], seed[0:32])
|
||||
copy(sk[32:64], pk[0:32])
|
||||
return
|
||||
}
|
||||
|
||||
func scalarBaseMult(sk []byte) (pk []byte) {
|
||||
var skey [32]byte
|
||||
var pkey [32]byte
|
||||
copy(skey[:], sk[0:32])
|
||||
var h edwards25519.ExtendedGroupElement
|
||||
edwards25519.GeScalarMultBase(&h, &skey)
|
||||
h.ToBytes(&pkey)
|
||||
pk = pkey[:]
|
||||
return
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
package nacl
|
||||
|
||||
// #cgo freebsd CFLAGS: -I/usr/local/include
|
||||
// #cgo freebsd LDFLAGS: -L/usr/local/lib
|
||||
// #cgo LDFLAGS: -lsodium
|
||||
// #include <sodium.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type KeyPair struct {
|
||||
pk *Buffer
|
||||
sk *Buffer
|
||||
}
|
||||
|
||||
// free this keypair from memory
|
||||
func (self *KeyPair) Free() {
|
||||
self.pk.Free()
|
||||
self.sk.Free()
|
||||
}
|
||||
|
||||
func (self *KeyPair) Secret() []byte {
|
||||
return self.sk.Bytes()
|
||||
}
|
||||
|
||||
func (self *KeyPair) Public() []byte {
|
||||
return self.pk.Bytes()
|
||||
}
|
||||
|
||||
func (self *KeyPair) Seed() []byte {
|
||||
seed_len := C.crypto_sign_seedbytes()
|
||||
return self.sk.Bytes()[:seed_len]
|
||||
}
|
||||
|
||||
// generate a keypair
|
||||
func GenSignKeypair() *KeyPair {
|
||||
sk_len := C.crypto_sign_secretkeybytes()
|
||||
sk := malloc(sk_len)
|
||||
pk_len := C.crypto_sign_publickeybytes()
|
||||
pk := malloc(pk_len)
|
||||
res := C.crypto_sign_keypair(pk.uchar(), sk.uchar())
|
||||
if res == 0 {
|
||||
return &KeyPair{pk, sk}
|
||||
}
|
||||
pk.Free()
|
||||
sk.Free()
|
||||
return nil
|
||||
}
|
||||
|
||||
// get public key from secret key
|
||||
func GetSignPubkey(sk []byte) ([]byte, error) {
|
||||
sk_len := C.crypto_sign_secretkeybytes()
|
||||
if C.size_t(len(sk)) != sk_len {
|
||||
return nil, errors.New(fmt.Sprintf("nacl.GetSignPubkey() invalid secret key size %d != %d", len(sk), sk_len))
|
||||
}
|
||||
|
||||
pk_len := C.crypto_sign_publickeybytes()
|
||||
pkbuff := malloc(pk_len)
|
||||
defer pkbuff.Free()
|
||||
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
//XXX: hack
|
||||
res := C.crypto_sign_seed_keypair(pkbuff.uchar(), skbuff.uchar(), skbuff.uchar())
|
||||
|
||||
if res != 0 {
|
||||
return nil, errors.New(fmt.Sprintf("nacl.GetSignPubkey() failed to get public key from secret key: %d", res))
|
||||
}
|
||||
|
||||
return pkbuff.Bytes(), nil
|
||||
}
|
||||
|
||||
// make keypair from seed
|
||||
func LoadSignKey(seed []byte) *KeyPair {
|
||||
seed_len := C.crypto_sign_seedbytes()
|
||||
if C.size_t(len(seed)) != seed_len {
|
||||
return nil
|
||||
}
|
||||
seedbuff := NewBuffer(seed)
|
||||
defer seedbuff.Free()
|
||||
pk_len := C.crypto_sign_publickeybytes()
|
||||
sk_len := C.crypto_sign_secretkeybytes()
|
||||
pkbuff := malloc(pk_len)
|
||||
skbuff := malloc(sk_len)
|
||||
res := C.crypto_sign_seed_keypair(pkbuff.uchar(), skbuff.uchar(), seedbuff.uchar())
|
||||
if res != 0 {
|
||||
pkbuff.Free()
|
||||
skbuff.Free()
|
||||
return nil
|
||||
}
|
||||
return &KeyPair{pkbuff, skbuff}
|
||||
}
|
||||
|
||||
func GenBoxKeypair() *KeyPair {
|
||||
sk_len := C.crypto_box_secretkeybytes()
|
||||
sk := malloc(sk_len)
|
||||
pk_len := C.crypto_box_publickeybytes()
|
||||
pk := malloc(pk_len)
|
||||
res := C.crypto_box_keypair(pk.uchar(), sk.uchar())
|
||||
if res == 0 {
|
||||
return &KeyPair{pk, sk}
|
||||
}
|
||||
pk.Free()
|
||||
sk.Free()
|
||||
return nil
|
||||
}
|
||||
|
||||
// get public key from secret key
|
||||
func GetBoxPubkey(sk []byte) []byte {
|
||||
sk_len := C.crypto_box_seedbytes()
|
||||
if C.size_t(len(sk)) != sk_len {
|
||||
return nil
|
||||
}
|
||||
|
||||
pk_len := C.crypto_box_publickeybytes()
|
||||
pkbuff := malloc(pk_len)
|
||||
defer pkbuff.Free()
|
||||
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
|
||||
// compute the public key
|
||||
C.crypto_scalarmult_base(pkbuff.uchar(), skbuff.uchar())
|
||||
|
||||
return pkbuff.Bytes()
|
||||
}
|
||||
|
||||
// load keypair from secret key
|
||||
func LoadBoxKey(sk []byte) *KeyPair {
|
||||
pk := GetBoxPubkey(sk)
|
||||
if pk == nil {
|
||||
return nil
|
||||
}
|
||||
pkbuff := NewBuffer(pk)
|
||||
skbuff := NewBuffer(sk)
|
||||
return &KeyPair{pkbuff, skbuff}
|
||||
}
|
||||
|
||||
// make keypair from seed
|
||||
func SeedBoxKey(seed []byte) *KeyPair {
|
||||
seed_len := C.crypto_box_seedbytes()
|
||||
if C.size_t(len(seed)) != seed_len {
|
||||
return nil
|
||||
}
|
||||
seedbuff := NewBuffer(seed)
|
||||
defer seedbuff.Free()
|
||||
pk_len := C.crypto_box_publickeybytes()
|
||||
sk_len := C.crypto_box_secretkeybytes()
|
||||
pkbuff := malloc(pk_len)
|
||||
skbuff := malloc(sk_len)
|
||||
res := C.crypto_box_seed_keypair(pkbuff.uchar(), skbuff.uchar(), seedbuff.uchar())
|
||||
if res != 0 {
|
||||
pkbuff.Free()
|
||||
skbuff.Free()
|
||||
return nil
|
||||
}
|
||||
return &KeyPair{pkbuff, skbuff}
|
||||
}
|
||||
|
||||
func (self *KeyPair) String() string {
|
||||
return fmt.Sprintf("pk=%s sk=%s", hex.EncodeToString(self.pk.Data()), hex.EncodeToString(self.sk.Data()))
|
||||
}
|
||||
|
||||
func CryptoSignPublicLen() int {
|
||||
return int(C.crypto_sign_publickeybytes())
|
||||
}
|
||||
|
||||
func CryptoSignSecretLen() int {
|
||||
return int(C.crypto_sign_secretkeybytes())
|
||||
}
|
||||
|
||||
func CryptoSignSeedLen() int {
|
||||
return int(C.crypto_sign_seedbytes())
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package nacl
|
||||
|
||||
// #cgo freebsd CFLAGS: -I/usr/local/include
|
||||
// #cgo freebsd LDFLAGS: -L/usr/local/lib
|
||||
// #cgo LDFLAGS: -lsodium
|
||||
// #include <sodium.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
// return how many bytes overhead does CryptoBox have
|
||||
func CryptoBoxOverhead() int {
|
||||
return int(C.crypto_box_macbytes())
|
||||
}
|
||||
|
||||
// size of crypto_box public keys
|
||||
func CryptoBoxPubKeySize() int {
|
||||
return int(C.crypto_box_publickeybytes())
|
||||
}
|
||||
|
||||
// size of crypto_box private keys
|
||||
func CryptoBoxPrivKeySize() int {
|
||||
return int(C.crypto_box_secretkeybytes())
|
||||
}
|
||||
|
||||
// size of crypto_sign public keys
|
||||
func CryptoSignPubKeySize() int {
|
||||
return int(C.crypto_sign_publickeybytes())
|
||||
}
|
||||
|
||||
// size of crypto_sign private keys
|
||||
func CryptoSignPrivKeySize() int {
|
||||
return int(C.crypto_sign_secretkeybytes())
|
||||
}
|
||||
|
||||
// initialize sodium
|
||||
func init() {
|
||||
status := C.sodium_init()
|
||||
if status == -1 {
|
||||
log.Fatalf("failed to initialize libsodium status=%d", status)
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package nacl
|
||||
|
||||
// #cgo freebsd CFLAGS: -I/usr/local/include
|
||||
// #cgo freebsd LDFLAGS: -L/usr/local/lib
|
||||
// #cgo LDFLAGS: -lsodium
|
||||
// #include <sodium.h>
|
||||
import "C"
|
||||
|
||||
func randbytes(size C.size_t) *Buffer {
|
||||
|
||||
buff := malloc(size)
|
||||
C.randombytes_buf(buff.ptr, size)
|
||||
return buff
|
||||
|
||||
}
|
||||
|
||||
func RandBytes(size int) []byte {
|
||||
if size > 0 {
|
||||
buff := randbytes(C.size_t(size))
|
||||
defer buff.Free()
|
||||
return buff.Bytes()
|
||||
}
|
||||
return nil
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
package nacl
|
||||
|
||||
// #cgo freebsd CFLAGS: -I/usr/local/include
|
||||
// #cgo freebsd LDFLAGS: -L/usr/local/lib
|
||||
// #cgo LDFLAGS: -lsodium
|
||||
// #include <sodium.h>
|
||||
import "C"
|
||||
|
||||
// sign data detached with secret key sk
|
||||
func CryptoSignDetached(msg, sk []byte) []byte {
|
||||
msgbuff := NewBuffer(msg)
|
||||
defer msgbuff.Free()
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
if skbuff.size != C.crypto_sign_bytes() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// allocate the signature buffer
|
||||
sig := malloc(C.crypto_sign_bytes())
|
||||
defer sig.Free()
|
||||
// compute signature
|
||||
siglen := C.ulonglong(0)
|
||||
res := C.crypto_sign_detached(sig.uchar(), &siglen, msgbuff.uchar(), C.ulonglong(msgbuff.size), skbuff.uchar())
|
||||
if res == 0 && siglen == C.ulonglong(C.crypto_sign_bytes()) {
|
||||
// return copy of signature buffer
|
||||
return sig.Bytes()
|
||||
}
|
||||
// failure to sign
|
||||
return nil
|
||||
}
|
||||
|
||||
// sign data with secret key sk
|
||||
// return detached sig
|
||||
// this uses crypto_sign instead pf crypto_sign_detached
|
||||
func CryptoSignFucky(msg, sk []byte) []byte {
|
||||
msgbuff := NewBuffer(msg)
|
||||
defer msgbuff.Free()
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
if skbuff.size != C.crypto_sign_bytes() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// allocate the signed message buffer
|
||||
sig := malloc(C.crypto_sign_bytes() + msgbuff.size)
|
||||
defer sig.Free()
|
||||
// compute signature
|
||||
siglen := C.ulonglong(0)
|
||||
res := C.crypto_sign(sig.uchar(), &siglen, msgbuff.uchar(), C.ulonglong(msgbuff.size), skbuff.uchar())
|
||||
if res == 0 {
|
||||
// return copy of signature inside the signed message
|
||||
offset := int(C.crypto_sign_bytes())
|
||||
return sig.Bytes()[:offset]
|
||||
}
|
||||
// failure to sign
|
||||
return nil
|
||||
}
|
@ -1,342 +0,0 @@
|
||||
package nacl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TOY encrypted authenticated stream protocol like tls
|
||||
|
||||
var BadHandshake = errors.New("Bad handshake")
|
||||
var ShortWrite = errors.New("short write")
|
||||
var ShortRead = errors.New("short read")
|
||||
var Closed = errors.New("socket closed")
|
||||
|
||||
// write boxes at 512 bytes at a time
|
||||
const DefaultMTU = 512
|
||||
|
||||
// wrapper arround crypto_box
|
||||
// provides an authenticated encrypted stream
|
||||
// this is a TOY
|
||||
type CryptoStream struct {
|
||||
// underlying stream to write on
|
||||
stream io.ReadWriteCloser
|
||||
// secret key seed
|
||||
key *KeyPair
|
||||
// public key of who we expect on the other end
|
||||
remote_pk []byte
|
||||
tx_nonce []byte
|
||||
rx_nonce []byte
|
||||
// box size
|
||||
mtu int
|
||||
}
|
||||
|
||||
func (cs *CryptoStream) Close() (err error) {
|
||||
if cs.key != nil {
|
||||
cs.key.Free()
|
||||
cs.key = nil
|
||||
}
|
||||
return cs.stream.Close()
|
||||
}
|
||||
|
||||
// implements io.Writer
|
||||
func (cs *CryptoStream) Write(data []byte) (n int, err error) {
|
||||
// let's split it up
|
||||
for n < len(data) && err == nil {
|
||||
if n+cs.mtu < len(data) {
|
||||
err = cs.writeSegment(data[n : n+cs.mtu])
|
||||
n += cs.mtu
|
||||
} else {
|
||||
err = cs.writeSegment(data[n:])
|
||||
if err == nil {
|
||||
n = len(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cs *CryptoStream) public() (p []byte) {
|
||||
p = cs.key.Public()
|
||||
return
|
||||
}
|
||||
|
||||
func (cs *CryptoStream) secret() (s []byte) {
|
||||
s = cs.key.Secret()
|
||||
return
|
||||
}
|
||||
|
||||
// read 1 segment
|
||||
func (cs *CryptoStream) readSegment() (s []byte, err error) {
|
||||
var stream_read int
|
||||
var seg []byte
|
||||
nl := NounceLen()
|
||||
msg := make([]byte, cs.mtu+nl)
|
||||
stream_read, err = cs.stream.Read(msg)
|
||||
seg, err = CryptoBoxOpen(msg[:stream_read], cs.rx_nonce, cs.secret(), cs.remote_pk)
|
||||
if err == nil {
|
||||
copy(cs.rx_nonce, seg[:nl])
|
||||
s = seg[nl:]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// write 1 segment encrypted
|
||||
// update nounce
|
||||
func (cs *CryptoStream) writeSegment(data []byte) (err error) {
|
||||
var segment []byte
|
||||
nl := NounceLen()
|
||||
msg := make([]byte, len(data)+nl)
|
||||
// generate next nounce
|
||||
nextNounce := NewBoxNounce()
|
||||
copy(msg, nextNounce)
|
||||
copy(msg[nl:], data)
|
||||
// encrypt segment with current nounce
|
||||
segment, err = CryptoBox(data, cs.tx_nonce, cs.remote_pk, cs.secret())
|
||||
var n int
|
||||
n, err = cs.stream.Write(segment)
|
||||
if n != len(segment) {
|
||||
// short write?
|
||||
err = ShortWrite
|
||||
return
|
||||
}
|
||||
// update nounce
|
||||
copy(cs.tx_nonce, nextNounce)
|
||||
return
|
||||
}
|
||||
|
||||
// implements io.Reader
|
||||
func (cs *CryptoStream) Read(data []byte) (n int, err error) {
|
||||
var seg []byte
|
||||
seg, err = cs.readSegment()
|
||||
if err == nil {
|
||||
if len(seg) <= len(data) {
|
||||
copy(data, seg)
|
||||
n = len(seg)
|
||||
} else {
|
||||
// too big?
|
||||
err = ShortRead
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// version 0 protocol magic
|
||||
var protocol_magic = []byte("BENIS|00")
|
||||
|
||||
// verify that a handshake is signed right and is in the correct format etc
|
||||
func verifyHandshake(hs, pk []byte) (valid bool) {
|
||||
ml := len(protocol_magic)
|
||||
// valid handshake?
|
||||
if bytes.Equal(hs[0:ml], protocol_magic) {
|
||||
// check pk
|
||||
pl := CryptoSignPublicLen()
|
||||
nl := NounceLen()
|
||||
if bytes.Equal(pk, hs[ml:ml+pl]) {
|
||||
// check signature
|
||||
msg := hs[0 : ml+pl+nl]
|
||||
sig := hs[ml+pl+nl:]
|
||||
valid = CryptoVerifyFucky(msg, sig, pk)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// get claimed public key from handshake
|
||||
func getPubkey(hs []byte) (pk []byte) {
|
||||
ml := len(protocol_magic)
|
||||
pl := CryptoSignPublicLen()
|
||||
pk = hs[ml : ml+pl]
|
||||
return
|
||||
}
|
||||
|
||||
func (cs *CryptoStream) genHandshake() (d []byte) {
|
||||
// protocol magic string version 00
|
||||
// Benis Encrypted Network Information Stream
|
||||
// :-DDDDD meme crypto
|
||||
d = append(d, protocol_magic...)
|
||||
// our public key
|
||||
d = append(d, cs.public()...)
|
||||
// nounce
|
||||
cs.tx_nonce = NewBoxNounce()
|
||||
d = append(d, cs.tx_nonce...)
|
||||
// sign protocol magic string, nounce and pubkey
|
||||
sig := CryptoSignFucky(d, cs.secret())
|
||||
// if sig is nil we'll just die
|
||||
d = append(d, sig...)
|
||||
return
|
||||
}
|
||||
|
||||
// extract nounce from handshake
|
||||
func getNounce(hs []byte) (n []byte) {
|
||||
ml := len(protocol_magic)
|
||||
pl := CryptoSignPublicLen()
|
||||
nl := NounceLen()
|
||||
n = hs[ml+pl : ml+pl+nl]
|
||||
return
|
||||
}
|
||||
|
||||
// initiate protocol handshake
|
||||
func (cs *CryptoStream) Handshake() (err error) {
|
||||
// send them our info
|
||||
hs := cs.genHandshake()
|
||||
var n int
|
||||
n, err = cs.stream.Write(hs)
|
||||
if n != len(hs) {
|
||||
err = ShortWrite
|
||||
return
|
||||
}
|
||||
// read thier info
|
||||
buff := make([]byte, len(hs))
|
||||
_, err = io.ReadFull(cs.stream, buff)
|
||||
|
||||
if cs.remote_pk == nil {
|
||||
// inbound
|
||||
pk := getPubkey(buff)
|
||||
cs.remote_pk = make([]byte, len(pk))
|
||||
copy(cs.remote_pk, pk)
|
||||
}
|
||||
|
||||
if !verifyHandshake(buff, cs.remote_pk) {
|
||||
// verification failed
|
||||
err = BadHandshake
|
||||
return
|
||||
}
|
||||
cs.rx_nonce = make([]byte, NounceLen())
|
||||
copy(cs.rx_nonce, getNounce(buff))
|
||||
return
|
||||
}
|
||||
|
||||
// create a client
|
||||
func Client(stream io.ReadWriteCloser, local_sk, remote_pk []byte) (c *CryptoStream) {
|
||||
c = &CryptoStream{
|
||||
stream: stream,
|
||||
mtu: DefaultMTU,
|
||||
}
|
||||
c.remote_pk = make([]byte, len(remote_pk))
|
||||
copy(c.remote_pk, remote_pk)
|
||||
c.key = LoadSignKey(local_sk)
|
||||
if c.key == nil {
|
||||
return nil
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
type CryptoConn struct {
|
||||
stream *CryptoStream
|
||||
conn net.Conn
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) Close() (err error) {
|
||||
err = cc.stream.Close()
|
||||
return
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) Write(d []byte) (n int, err error) {
|
||||
return cc.stream.Write(d)
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) Read(d []byte) (n int, err error) {
|
||||
return cc.stream.Read(d)
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) LocalAddr() net.Addr {
|
||||
return cc.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) RemoteAddr() net.Addr {
|
||||
return cc.conn.RemoteAddr()
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) SetDeadline(t time.Time) (err error) {
|
||||
return cc.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) SetReadDeadline(t time.Time) (err error) {
|
||||
return cc.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) SetWriteDeadline(t time.Time) (err error) {
|
||||
return cc.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
type CryptoListener struct {
|
||||
l net.Listener
|
||||
handshake chan net.Conn
|
||||
accepted chan *CryptoConn
|
||||
trust func(pk []byte) bool
|
||||
key *KeyPair
|
||||
}
|
||||
|
||||
func (cl *CryptoListener) Close() (err error) {
|
||||
err = cl.l.Close()
|
||||
close(cl.accepted)
|
||||
close(cl.handshake)
|
||||
cl.key.Free()
|
||||
cl.key = nil
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *CryptoListener) acceptInbound() {
|
||||
for {
|
||||
c, err := cl.l.Accept()
|
||||
if err == nil {
|
||||
cl.handshake <- c
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (cl *CryptoListener) runChans() {
|
||||
for {
|
||||
select {
|
||||
case c := <-cl.handshake:
|
||||
go func() {
|
||||
s := &CryptoStream{
|
||||
stream: c,
|
||||
mtu: DefaultMTU,
|
||||
key: cl.key,
|
||||
}
|
||||
err := s.Handshake()
|
||||
if err == nil {
|
||||
// we gud handshake was okay
|
||||
if cl.trust(s.remote_pk) {
|
||||
// the key is trusted okay
|
||||
cl.accepted <- &CryptoConn{stream: s, conn: c}
|
||||
} else {
|
||||
// not trusted, close connection
|
||||
s.Close()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// accept inbound authenticated and trusted connections
|
||||
func (cl *CryptoListener) Accept() (c net.Conn, err error) {
|
||||
var ok bool
|
||||
c, ok = <-cl.accepted
|
||||
if !ok {
|
||||
err = Closed
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// create a listener
|
||||
func Server(l net.Listener, local_sk []byte, trust func(pk []byte) bool) (s *CryptoListener) {
|
||||
s = &CryptoListener{
|
||||
l: l,
|
||||
trust: trust,
|
||||
handshake: make(chan net.Conn),
|
||||
accepted: make(chan *CryptoConn),
|
||||
}
|
||||
s.key = LoadSignKey(local_sk)
|
||||
go s.runChans()
|
||||
go s.acceptInbound()
|
||||
return
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
package nacl
|
||||
|
||||
// #cgo freebsd CFLAGS: -I/usr/local/include
|
||||
// #cgo freebsd LDFLAGS: -L/usr/local/lib
|
||||
// #cgo LDFLAGS: -lsodium
|
||||
// #include <sodium.h>
|
||||
import "C"
|
||||
|
||||
// verify a fucky detached sig
|
||||
func CryptoVerifyFucky(msg, sig, pk []byte) bool {
|
||||
var smsg []byte
|
||||
smsg = append(smsg, sig...)
|
||||
smsg = append(smsg, msg...)
|
||||
return CryptoVerify(smsg, pk)
|
||||
}
|
||||
|
||||
// verify a signed message
|
||||
func CryptoVerify(smsg, pk []byte) bool {
|
||||
smsg_buff := NewBuffer(smsg)
|
||||
defer smsg_buff.Free()
|
||||
pk_buff := NewBuffer(pk)
|
||||
defer pk_buff.Free()
|
||||
|
||||
if pk_buff.size != C.crypto_sign_publickeybytes() {
|
||||
return false
|
||||
}
|
||||
mlen := C.ulonglong(0)
|
||||
msg := malloc(C.size_t(len(smsg)))
|
||||
defer msg.Free()
|
||||
smlen := C.ulonglong(smsg_buff.size)
|
||||
return C.crypto_sign_open(msg.uchar(), &mlen, smsg_buff.uchar(), smlen, pk_buff.uchar()) != -1
|
||||
}
|
||||
|
||||
// verfiy a detached signature
|
||||
// return true on valid otherwise false
|
||||
func CryptoVerifyDetached(msg, sig, pk []byte) bool {
|
||||
msg_buff := NewBuffer(msg)
|
||||
defer msg_buff.Free()
|
||||
sig_buff := NewBuffer(sig)
|
||||
defer sig_buff.Free()
|
||||
pk_buff := NewBuffer(pk)
|
||||
defer pk_buff.Free()
|
||||
|
||||
if pk_buff.size != C.crypto_sign_publickeybytes() {
|
||||
return false
|
||||
}
|
||||
|
||||
// invalid sig size
|
||||
if sig_buff.size != C.crypto_sign_bytes() {
|
||||
return false
|
||||
}
|
||||
return C.crypto_sign_verify_detached(sig_buff.uchar(), msg_buff.uchar(), C.ulonglong(len(msg)), pk_buff.uchar()) == 0
|
||||
}
|
@ -1,8 +1,13 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"nntpchan/lib/crypto/nacl"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
)
|
||||
|
||||
// generate random bytes
|
||||
var RandBytes = nacl.RandBytes
|
||||
func RandBytes(n int) []byte {
|
||||
b := make([]byte, n)
|
||||
io.ReadFull(rand.Reader, b)
|
||||
return b
|
||||
}
|
||||
|
@ -5,14 +5,14 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"nntpchan/lib/crypto/nacl"
|
||||
"nntpchan/lib/crypto"
|
||||
)
|
||||
|
||||
// given an address
|
||||
// generate a new encryption key for it
|
||||
// return the encryption key and the encrypted address
|
||||
func NewAddrEnc(addr string) (string, string) {
|
||||
key_bytes := nacl.RandBytes(encAddrBytes())
|
||||
key_bytes := crypto.RandBytes(encAddrBytes())
|
||||
key := base64.StdEncoding.EncodeToString(key_bytes)
|
||||
return key, EncAddr(addr, key)
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"crypto/sha512"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"nntpchan/lib/crypto/nacl"
|
||||
"nntpchan/lib/crypto"
|
||||
)
|
||||
|
||||
// generate a login salt for nntp users
|
||||
@ -25,5 +25,5 @@ func NntpLoginCredHash(passwd, salt string) (str string) {
|
||||
|
||||
// make a random string
|
||||
func randStr(length int) string {
|
||||
return hex.EncodeToString(nacl.RandBytes(length))[length:]
|
||||
return hex.EncodeToString(crypto.RandBytes(length))[length:]
|
||||
}
|
||||
|
10
contrib/backends/nntpchand/src/vendor/edwards25519/BUILD.bazel
vendored
Normal file
10
contrib/backends/nntpchand/src/vendor/edwards25519/BUILD.bazel
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"const.go",
|
||||
"edwards25519.go",
|
||||
],
|
||||
visibility = ["//sign:__subpackages__"],
|
||||
)
|
27
contrib/backends/nntpchand/src/vendor/edwards25519/LICENSE
vendored
Normal file
27
contrib/backends/nntpchand/src/vendor/edwards25519/LICENSE
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2017 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
1422
contrib/backends/nntpchand/src/vendor/edwards25519/const.go
vendored
Normal file
1422
contrib/backends/nntpchand/src/vendor/edwards25519/const.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1769
contrib/backends/nntpchand/src/vendor/edwards25519/edwards25519.go
vendored
Normal file
1769
contrib/backends/nntpchand/src/vendor/edwards25519/edwards25519.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
contrib/backends/nntpchand/src/vendor/edwards25519/readme.txt
vendored
Normal file
1
contrib/backends/nntpchand/src/vendor/edwards25519/readme.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
cloned from https://github.com/kevinburke/nacl/commit/38707d146a0b97e13e5de807a3ad62a933f7668c
|
181
contrib/backends/nntpchand/src/vendor/golang.org/x/crypto/ed25519/ed25519.go
generated
vendored
Normal file
181
contrib/backends/nntpchand/src/vendor/golang.org/x/crypto/ed25519/ed25519.go
generated
vendored
Normal file
@ -0,0 +1,181 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ed25519 implements the Ed25519 signature algorithm. See
|
||||
// https://ed25519.cr.yp.to/.
|
||||
//
|
||||
// These functions are also compatible with the “Ed25519” function defined in
|
||||
// https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-05.
|
||||
package ed25519
|
||||
|
||||
// This code is a port of the public domain, “ref10” implementation of ed25519
|
||||
// from SUPERCOP.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
cryptorand "crypto/rand"
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/crypto/ed25519/internal/edwards25519"
|
||||
)
|
||||
|
||||
const (
|
||||
// PublicKeySize is the size, in bytes, of public keys as used in this package.
|
||||
PublicKeySize = 32
|
||||
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
|
||||
PrivateKeySize = 64
|
||||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
||||
SignatureSize = 64
|
||||
)
|
||||
|
||||
// PublicKey is the type of Ed25519 public keys.
|
||||
type PublicKey []byte
|
||||
|
||||
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
|
||||
type PrivateKey []byte
|
||||
|
||||
// Public returns the PublicKey corresponding to priv.
|
||||
func (priv PrivateKey) Public() crypto.PublicKey {
|
||||
publicKey := make([]byte, PublicKeySize)
|
||||
copy(publicKey, priv[32:])
|
||||
return PublicKey(publicKey)
|
||||
}
|
||||
|
||||
// Sign signs the given message with priv.
|
||||
// Ed25519 performs two passes over messages to be signed and therefore cannot
|
||||
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
|
||||
// indicate the message hasn't been hashed. This can be achieved by passing
|
||||
// crypto.Hash(0) as the value for opts.
|
||||
func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
|
||||
if opts.HashFunc() != crypto.Hash(0) {
|
||||
return nil, errors.New("ed25519: cannot sign hashed message")
|
||||
}
|
||||
|
||||
return Sign(priv, message), nil
|
||||
}
|
||||
|
||||
// GenerateKey generates a public/private key pair using entropy from rand.
|
||||
// If rand is nil, crypto/rand.Reader will be used.
|
||||
func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) {
|
||||
if rand == nil {
|
||||
rand = cryptorand.Reader
|
||||
}
|
||||
|
||||
privateKey = make([]byte, PrivateKeySize)
|
||||
publicKey = make([]byte, PublicKeySize)
|
||||
_, err = io.ReadFull(rand, privateKey[:32])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
digest := sha512.Sum512(privateKey[:32])
|
||||
digest[0] &= 248
|
||||
digest[31] &= 127
|
||||
digest[31] |= 64
|
||||
|
||||
var A edwards25519.ExtendedGroupElement
|
||||
var hBytes [32]byte
|
||||
copy(hBytes[:], digest[:])
|
||||
edwards25519.GeScalarMultBase(&A, &hBytes)
|
||||
var publicKeyBytes [32]byte
|
||||
A.ToBytes(&publicKeyBytes)
|
||||
|
||||
copy(privateKey[32:], publicKeyBytes[:])
|
||||
copy(publicKey, publicKeyBytes[:])
|
||||
|
||||
return publicKey, privateKey, nil
|
||||
}
|
||||
|
||||
// Sign signs the message with privateKey and returns a signature. It will
|
||||
// panic if len(privateKey) is not PrivateKeySize.
|
||||
func Sign(privateKey PrivateKey, message []byte) []byte {
|
||||
if l := len(privateKey); l != PrivateKeySize {
|
||||
panic("ed25519: bad private key length: " + strconv.Itoa(l))
|
||||
}
|
||||
|
||||
h := sha512.New()
|
||||
h.Write(privateKey[:32])
|
||||
|
||||
var digest1, messageDigest, hramDigest [64]byte
|
||||
var expandedSecretKey [32]byte
|
||||
h.Sum(digest1[:0])
|
||||
copy(expandedSecretKey[:], digest1[:])
|
||||
expandedSecretKey[0] &= 248
|
||||
expandedSecretKey[31] &= 63
|
||||
expandedSecretKey[31] |= 64
|
||||
|
||||
h.Reset()
|
||||
h.Write(digest1[32:])
|
||||
h.Write(message)
|
||||
h.Sum(messageDigest[:0])
|
||||
|
||||
var messageDigestReduced [32]byte
|
||||
edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
|
||||
var R edwards25519.ExtendedGroupElement
|
||||
edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
|
||||
|
||||
var encodedR [32]byte
|
||||
R.ToBytes(&encodedR)
|
||||
|
||||
h.Reset()
|
||||
h.Write(encodedR[:])
|
||||
h.Write(privateKey[32:])
|
||||
h.Write(message)
|
||||
h.Sum(hramDigest[:0])
|
||||
var hramDigestReduced [32]byte
|
||||
edwards25519.ScReduce(&hramDigestReduced, &hramDigest)
|
||||
|
||||
var s [32]byte
|
||||
edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced)
|
||||
|
||||
signature := make([]byte, SignatureSize)
|
||||
copy(signature[:], encodedR[:])
|
||||
copy(signature[32:], s[:])
|
||||
|
||||
return signature
|
||||
}
|
||||
|
||||
// Verify reports whether sig is a valid signature of message by publicKey. It
|
||||
// will panic if len(publicKey) is not PublicKeySize.
|
||||
func Verify(publicKey PublicKey, message, sig []byte) bool {
|
||||
if l := len(publicKey); l != PublicKeySize {
|
||||
panic("ed25519: bad public key length: " + strconv.Itoa(l))
|
||||
}
|
||||
|
||||
if len(sig) != SignatureSize || sig[63]&224 != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
var A edwards25519.ExtendedGroupElement
|
||||
var publicKeyBytes [32]byte
|
||||
copy(publicKeyBytes[:], publicKey)
|
||||
if !A.FromBytes(&publicKeyBytes) {
|
||||
return false
|
||||
}
|
||||
edwards25519.FeNeg(&A.X, &A.X)
|
||||
edwards25519.FeNeg(&A.T, &A.T)
|
||||
|
||||
h := sha512.New()
|
||||
h.Write(sig[:32])
|
||||
h.Write(publicKey[:])
|
||||
h.Write(message)
|
||||
var digest [64]byte
|
||||
h.Sum(digest[:0])
|
||||
|
||||
var hReduced [32]byte
|
||||
edwards25519.ScReduce(&hReduced, &digest)
|
||||
|
||||
var R edwards25519.ProjectiveGroupElement
|
||||
var b [32]byte
|
||||
copy(b[:], sig[32:])
|
||||
edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b)
|
||||
|
||||
var checkR [32]byte
|
||||
R.ToBytes(&checkR)
|
||||
return bytes.Equal(sig[:32], checkR[:])
|
||||
}
|
183
contrib/backends/nntpchand/src/vendor/golang.org/x/crypto/ed25519/ed25519_test.go
generated
vendored
Normal file
183
contrib/backends/nntpchand/src/vendor/golang.org/x/crypto/ed25519/ed25519_test.go
generated
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ed25519
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/ed25519/internal/edwards25519"
|
||||
)
|
||||
|
||||
type zeroReader struct{}
|
||||
|
||||
func (zeroReader) Read(buf []byte) (int, error) {
|
||||
for i := range buf {
|
||||
buf[i] = 0
|
||||
}
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
func TestUnmarshalMarshal(t *testing.T) {
|
||||
pub, _, _ := GenerateKey(rand.Reader)
|
||||
|
||||
var A edwards25519.ExtendedGroupElement
|
||||
var pubBytes [32]byte
|
||||
copy(pubBytes[:], pub)
|
||||
if !A.FromBytes(&pubBytes) {
|
||||
t.Fatalf("ExtendedGroupElement.FromBytes failed")
|
||||
}
|
||||
|
||||
var pub2 [32]byte
|
||||
A.ToBytes(&pub2)
|
||||
|
||||
if pubBytes != pub2 {
|
||||
t.Errorf("FromBytes(%v)->ToBytes does not round-trip, got %x\n", pubBytes, pub2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignVerify(t *testing.T) {
|
||||
var zero zeroReader
|
||||
public, private, _ := GenerateKey(zero)
|
||||
|
||||
message := []byte("test message")
|
||||
sig := Sign(private, message)
|
||||
if !Verify(public, message, sig) {
|
||||
t.Errorf("valid signature rejected")
|
||||
}
|
||||
|
||||
wrongMessage := []byte("wrong message")
|
||||
if Verify(public, wrongMessage, sig) {
|
||||
t.Errorf("signature of different message accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCryptoSigner(t *testing.T) {
|
||||
var zero zeroReader
|
||||
public, private, _ := GenerateKey(zero)
|
||||
|
||||
signer := crypto.Signer(private)
|
||||
|
||||
publicInterface := signer.Public()
|
||||
public2, ok := publicInterface.(PublicKey)
|
||||
if !ok {
|
||||
t.Fatalf("expected PublicKey from Public() but got %T", publicInterface)
|
||||
}
|
||||
|
||||
if !bytes.Equal(public, public2) {
|
||||
t.Errorf("public keys do not match: original:%x vs Public():%x", public, public2)
|
||||
}
|
||||
|
||||
message := []byte("message")
|
||||
var noHash crypto.Hash
|
||||
signature, err := signer.Sign(zero, message, noHash)
|
||||
if err != nil {
|
||||
t.Fatalf("error from Sign(): %s", err)
|
||||
}
|
||||
|
||||
if !Verify(public, message, signature) {
|
||||
t.Errorf("Verify failed on signature from Sign()")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGolden(t *testing.T) {
|
||||
// sign.input.gz is a selection of test cases from
|
||||
// https://ed25519.cr.yp.to/python/sign.input
|
||||
testDataZ, err := os.Open("testdata/sign.input.gz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer testDataZ.Close()
|
||||
testData, err := gzip.NewReader(testDataZ)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer testData.Close()
|
||||
|
||||
scanner := bufio.NewScanner(testData)
|
||||
lineNo := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
lineNo++
|
||||
|
||||
line := scanner.Text()
|
||||
parts := strings.Split(line, ":")
|
||||
if len(parts) != 5 {
|
||||
t.Fatalf("bad number of parts on line %d", lineNo)
|
||||
}
|
||||
|
||||
privBytes, _ := hex.DecodeString(parts[0])
|
||||
pubKey, _ := hex.DecodeString(parts[1])
|
||||
msg, _ := hex.DecodeString(parts[2])
|
||||
sig, _ := hex.DecodeString(parts[3])
|
||||
// The signatures in the test vectors also include the message
|
||||
// at the end, but we just want R and S.
|
||||
sig = sig[:SignatureSize]
|
||||
|
||||
if l := len(pubKey); l != PublicKeySize {
|
||||
t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l)
|
||||
}
|
||||
|
||||
var priv [PrivateKeySize]byte
|
||||
copy(priv[:], privBytes)
|
||||
copy(priv[32:], pubKey)
|
||||
|
||||
sig2 := Sign(priv[:], msg)
|
||||
if !bytes.Equal(sig, sig2[:]) {
|
||||
t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2)
|
||||
}
|
||||
|
||||
if !Verify(pubKey, msg, sig2) {
|
||||
t.Errorf("signature failed to verify on line %d", lineNo)
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
t.Fatalf("error reading test data: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKeyGeneration(b *testing.B) {
|
||||
var zero zeroReader
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, _, err := GenerateKey(zero); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSigning(b *testing.B) {
|
||||
var zero zeroReader
|
||||
_, priv, err := GenerateKey(zero)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
message := []byte("Hello, world!")
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Sign(priv, message)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkVerification(b *testing.B) {
|
||||
var zero zeroReader
|
||||
pub, priv, err := GenerateKey(zero)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
message := []byte("Hello, world!")
|
||||
signature := Sign(priv, message)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Verify(pub, message, signature)
|
||||
}
|
||||
}
|
1422
contrib/backends/nntpchand/src/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
generated
vendored
Normal file
1422
contrib/backends/nntpchand/src/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1771
contrib/backends/nntpchand/src/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
Normal file
1771
contrib/backends/nntpchand/src/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
contrib/backends/nntpchand/src/vendor/golang.org/x/crypto/ed25519/testdata/sign.input.gz
generated
vendored
Normal file
BIN
contrib/backends/nntpchand/src/vendor/golang.org/x/crypto/ed25519/testdata/sign.input.gz
generated
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user