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 {
|
if h == nil {
|
||||||
panic("fuck.hash.Sum == nil")
|
panic("fuck.hash.Sum == nil")
|
||||||
}
|
}
|
||||||
kp := nacl.LoadSignKey(fucky.k)
|
|
||||||
defer kp.Free()
|
_, sec := nacl.SeedToKeyPair(fucky.k)
|
||||||
sk := kp.Secret()
|
sig := nacl.CryptoSignFucky(h, sec)
|
||||||
sig := nacl.CryptoSignFucky(h, sk)
|
|
||||||
if sig == nil {
|
if sig == nil {
|
||||||
panic("fucky signer's call to nacl.CryptoSignFucky returned 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) {
|
func (fucky *fuckyNacl) Verify(sig Signature) (valid bool) {
|
||||||
h := fucky.hash.Sum(nil)
|
h := fucky.hash.Sum(nil)
|
||||||
if h == nil {
|
if h == nil {
|
||||||
panic("fuck.hash.Sum == nil")
|
panic("fucky.hash.Sum == nil")
|
||||||
}
|
}
|
||||||
valid = nacl.CryptoVerifyFucky(h, sig, fucky.k)
|
valid = nacl.CryptoVerifyFucky(h, sig, fucky.k)
|
||||||
fucky.resetState()
|
fucky.resetState()
|
||||||
@ -66,17 +65,13 @@ func CreateVerifier(pk []byte) Verifer {
|
|||||||
|
|
||||||
// get the public component given the secret key
|
// get the public component given the secret key
|
||||||
func ToPublic(sk []byte) (pk []byte) {
|
func ToPublic(sk []byte) (pk []byte) {
|
||||||
kp := nacl.LoadSignKey(sk)
|
pk, _ = nacl.SeedToKeyPair(sk)
|
||||||
defer kp.Free()
|
|
||||||
pk = kp.Public()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a standard keypair
|
// create a standard keypair
|
||||||
func GenKeypair() (pk, sk []byte) {
|
func GenKeypair() (pk, sk []byte) {
|
||||||
kp := nacl.GenSignKeypair()
|
sk = RandBytes(32)
|
||||||
defer kp.Free()
|
pk, _ = nacl.SeedToKeyPair(sk)
|
||||||
pk = kp.Public()
|
|
||||||
sk = kp.Seed()
|
|
||||||
return
|
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
|
package crypto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"nntpchan/lib/crypto/nacl"
|
"crypto/rand"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
// generate random bytes
|
// 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"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"nntpchan/lib/crypto/nacl"
|
"nntpchan/lib/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// given an address
|
// given an address
|
||||||
// generate a new encryption key for it
|
// generate a new encryption key for it
|
||||||
// return the encryption key and the encrypted address
|
// return the encryption key and the encrypted address
|
||||||
func NewAddrEnc(addr string) (string, string) {
|
func NewAddrEnc(addr string) (string, string) {
|
||||||
key_bytes := nacl.RandBytes(encAddrBytes())
|
key_bytes := crypto.RandBytes(encAddrBytes())
|
||||||
key := base64.StdEncoding.EncodeToString(key_bytes)
|
key := base64.StdEncoding.EncodeToString(key_bytes)
|
||||||
return key, EncAddr(addr, key)
|
return key, EncAddr(addr, key)
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"nntpchan/lib/crypto/nacl"
|
"nntpchan/lib/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// generate a login salt for nntp users
|
// generate a login salt for nntp users
|
||||||
@ -25,5 +25,5 @@ func NntpLoginCredHash(passwd, salt string) (str string) {
|
|||||||
|
|
||||||
// make a random string
|
// make a random string
|
||||||
func randStr(length int) 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