Archived
1
0
This commit is contained in:
Jeff Becker 2017-08-25 10:43:29 -04:00
parent cc5d94ee5f
commit d61228215e
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05
8 changed files with 528 additions and 538 deletions

View File

@ -7,89 +7,89 @@ package nacl
import "C" import "C"
import ( import (
"errors" "errors"
) )
// encrypts a message to a user given their public key is known // encrypts a message to a user given their public key is known
// returns an encrypted box // returns an encrypted box
func CryptoBox(msg, nounce, pk, sk []byte) ([]byte, error) { func CryptoBox(msg, nounce, pk, sk []byte) ([]byte, error) {
msgbuff := NewBuffer(msg) msgbuff := NewBuffer(msg)
defer msgbuff.Free() defer msgbuff.Free()
// check sizes // check sizes
if len(pk) != int(C.crypto_box_publickeybytes()) { if len(pk) != int(C.crypto_box_publickeybytes()) {
err := errors.New("len(pk) != crypto_box_publickey_bytes") err := errors.New("len(pk) != crypto_box_publickey_bytes")
return nil, err return nil, err
} }
if len(sk) != int(C.crypto_box_secretkeybytes()) { if len(sk) != int(C.crypto_box_secretkeybytes()) {
err := errors.New("len(sk) != crypto_box_secretkey_bytes") err := errors.New("len(sk) != crypto_box_secretkey_bytes")
return nil, err return nil, err
} }
if len(nounce) != int(C.crypto_box_macbytes()) { if len(nounce) != int(C.crypto_box_macbytes()) {
err := errors.New ("len(nounce) != crypto_box_macbytes()") err := errors.New("len(nounce) != crypto_box_macbytes()")
return nil, err return nil, err
} }
pkbuff := NewBuffer(pk) pkbuff := NewBuffer(pk)
defer pkbuff.Free() defer pkbuff.Free()
skbuff := NewBuffer(sk) skbuff := NewBuffer(sk)
defer skbuff.Free() defer skbuff.Free()
nouncebuff := NewBuffer(nounce) nouncebuff := NewBuffer(nounce)
defer nouncebuff.Free() defer nouncebuff.Free()
resultbuff := malloc(msgbuff.size + nouncebuff.size) resultbuff := malloc(msgbuff.size + nouncebuff.size)
defer resultbuff.Free() defer resultbuff.Free()
res := C.crypto_box_easy(resultbuff.uchar(), msgbuff.uchar(), C.ulonglong(msgbuff.size), nouncebuff.uchar(), pkbuff.uchar(), skbuff.uchar()) res := C.crypto_box_easy(resultbuff.uchar(), msgbuff.uchar(), C.ulonglong(msgbuff.size), nouncebuff.uchar(), pkbuff.uchar(), skbuff.uchar())
if res != 0 { if res != 0 {
err := errors.New("crypto_box_easy failed") err := errors.New("crypto_box_easy failed")
return nil, err return nil, err
} }
return resultbuff.Bytes(), nil return resultbuff.Bytes(), nil
} }
// open an encrypted box // open an encrypted box
func CryptoBoxOpen(box, nounce, sk, pk []byte) ([]byte, error) { func CryptoBoxOpen(box, nounce, sk, pk []byte) ([]byte, error) {
boxbuff := NewBuffer(box) boxbuff := NewBuffer(box)
defer boxbuff.Free() defer boxbuff.Free()
// check sizes // check sizes
if len(pk) != int(C.crypto_box_publickeybytes()) { if len(pk) != int(C.crypto_box_publickeybytes()) {
err := errors.New("len(pk) != crypto_box_publickey_bytes") err := errors.New("len(pk) != crypto_box_publickey_bytes")
return nil, err return nil, err
} }
if len(sk) != int(C.crypto_box_secretkeybytes()) { if len(sk) != int(C.crypto_box_secretkeybytes()) {
err := errors.New("len(sk) != crypto_box_secretkey_bytes") err := errors.New("len(sk) != crypto_box_secretkey_bytes")
return nil, err return nil, err
} }
if len(nounce) != int(C.crypto_box_macbytes()) { if len(nounce) != int(C.crypto_box_macbytes()) {
err := errors.New("len(nounce) != crypto_box_macbytes()") err := errors.New("len(nounce) != crypto_box_macbytes()")
return nil, err return nil, err
} }
pkbuff := NewBuffer(pk) pkbuff := NewBuffer(pk)
defer pkbuff.Free() defer pkbuff.Free()
skbuff := NewBuffer(sk) skbuff := NewBuffer(sk)
defer skbuff.Free() defer skbuff.Free()
nouncebuff := NewBuffer(nounce) nouncebuff := NewBuffer(nounce)
defer nouncebuff.Free() defer nouncebuff.Free()
resultbuff := malloc(boxbuff.size - nouncebuff.size) resultbuff := malloc(boxbuff.size - nouncebuff.size)
defer resultbuff.Free() defer resultbuff.Free()
// decrypt // decrypt
res := C.crypto_box_open_easy(resultbuff.uchar(), boxbuff.uchar(), C.ulonglong(boxbuff.size), nouncebuff.uchar(), pkbuff.uchar(), skbuff.uchar()) res := C.crypto_box_open_easy(resultbuff.uchar(), boxbuff.uchar(), C.ulonglong(boxbuff.size), nouncebuff.uchar(), pkbuff.uchar(), skbuff.uchar())
if res != 0 { if res != 0 {
return nil, errors.New("crypto_box_open_easy failed") return nil, errors.New("crypto_box_open_easy failed")
} }
// return result // return result
return resultbuff.Bytes(), nil return resultbuff.Bytes(), nil
} }
// generate a new nounce // generate a new nounce
func NewBoxNounce() []byte { func NewBoxNounce() []byte {
return RandBytes(NounceLen()) return RandBytes(NounceLen())
} }
// length of a nounce // length of a nounce
func NounceLen() int { func NounceLen() int {
return int(C.crypto_box_macbytes()) return int(C.crypto_box_macbytes())
} }

View File

@ -10,78 +10,77 @@ package nacl
import "C" import "C"
import ( import (
"encoding/hex" "encoding/hex"
"reflect" "reflect"
"unsafe" "unsafe"
) )
// wrapper arround malloc/free // wrapper arround malloc/free
type Buffer struct { type Buffer struct {
ptr unsafe.Pointer; ptr unsafe.Pointer
length C.int; length C.int
size C.size_t; size C.size_t
} }
// wrapper arround nacl.malloc // wrapper arround nacl.malloc
func Malloc(size int) *Buffer { func Malloc(size int) *Buffer {
if size > 0 { if size > 0 {
return malloc(C.size_t(size)) return malloc(C.size_t(size))
} }
return nil return nil
} }
// does not check for negatives // does not check for negatives
func malloc(size C.size_t) *Buffer { func malloc(size C.size_t) *Buffer {
ptr := C.malloc(size) ptr := C.malloc(size)
C.sodium_memzero(ptr, size) C.sodium_memzero(ptr, size)
buffer := &Buffer{ptr: ptr, size: size , length: C.int(size)} buffer := &Buffer{ptr: ptr, size: size, length: C.int(size)}
return buffer return buffer
} }
// create a new buffer copying from a byteslice // create a new buffer copying from a byteslice
func NewBuffer(buff []byte) *Buffer { func NewBuffer(buff []byte) *Buffer {
buffer := Malloc(len(buff)) buffer := Malloc(len(buff))
if buffer == nil { if buffer == nil {
return nil return nil
} }
if copy(buffer.Data(), buff) != len(buff) { if copy(buffer.Data(), buff) != len(buff) {
return nil return nil
} }
return buffer return buffer
} }
func (self *Buffer) uchar() *C.uchar { func (self *Buffer) uchar() *C.uchar {
return C.deref_uchar(self.ptr) return C.deref_uchar(self.ptr)
} }
func (self *Buffer) Length() int { func (self *Buffer) Length() int {
return int(self.length) return int(self.length)
} }
// get immutable byte slice // get immutable byte slice
func (self *Buffer) Bytes() []byte { func (self *Buffer) Bytes() []byte {
buff := make([]byte, self.Length()) buff := make([]byte, self.Length())
copy(buff, self.Data()) copy(buff, self.Data())
return buff return buff
} }
// get underlying byte slice // get underlying byte slice
func (self *Buffer) Data() []byte { func (self *Buffer) Data() []byte {
hdr := reflect.SliceHeader{ hdr := reflect.SliceHeader{
Data: uintptr(self.ptr), Data: uintptr(self.ptr),
Len: self.Length(), Len: self.Length(),
Cap: self.Length(), Cap: self.Length(),
} }
return *(*[]byte)(unsafe.Pointer(&hdr)) return *(*[]byte)(unsafe.Pointer(&hdr))
} }
func (self *Buffer) String() string { func (self *Buffer) String() string {
return hex.EncodeToString(self.Data()) return hex.EncodeToString(self.Data())
} }
// zero out memory and then free // zero out memory and then free
func (self *Buffer) Free() { func (self *Buffer) Free() {
C.sodium_memzero(self.ptr, self.size) C.sodium_memzero(self.ptr, self.size)
C.free(self.ptr) C.free(self.ptr)
} }

View File

@ -7,174 +7,172 @@ package nacl
import "C" import "C"
import ( import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
) )
type KeyPair struct { type KeyPair struct {
pk *Buffer pk *Buffer
sk *Buffer sk *Buffer
} }
// free this keypair from memory // free this keypair from memory
func (self *KeyPair) Free() { func (self *KeyPair) Free() {
self.pk.Free() self.pk.Free()
self.sk.Free() self.sk.Free()
} }
func (self *KeyPair) Secret() []byte { func (self *KeyPair) Secret() []byte {
return self.sk.Bytes() return self.sk.Bytes()
} }
func (self *KeyPair) Public() []byte { func (self *KeyPair) Public() []byte {
return self.pk.Bytes() return self.pk.Bytes()
} }
func (self *KeyPair) Seed() []byte { func (self *KeyPair) Seed() []byte {
seed_len := C.crypto_sign_seedbytes() seed_len := C.crypto_sign_seedbytes()
return self.sk.Bytes()[:seed_len] return self.sk.Bytes()[:seed_len]
} }
// generate a keypair // generate a keypair
func GenSignKeypair() *KeyPair { func GenSignKeypair() *KeyPair {
sk_len := C.crypto_sign_secretkeybytes() sk_len := C.crypto_sign_secretkeybytes()
sk := malloc(sk_len) sk := malloc(sk_len)
pk_len := C.crypto_sign_publickeybytes() pk_len := C.crypto_sign_publickeybytes()
pk := malloc(pk_len) pk := malloc(pk_len)
res := C.crypto_sign_keypair(pk.uchar(), sk.uchar()) res := C.crypto_sign_keypair(pk.uchar(), sk.uchar())
if res == 0 { if res == 0 {
return &KeyPair{pk,sk} return &KeyPair{pk, sk}
} }
pk.Free() pk.Free()
sk.Free() sk.Free()
return nil return nil
} }
// get public key from secret key // get public key from secret key
func GetSignPubkey(sk []byte) ([]byte, error) { func GetSignPubkey(sk []byte) ([]byte, error) {
sk_len := C.crypto_sign_secretkeybytes() sk_len := C.crypto_sign_secretkeybytes()
if C.size_t(len(sk)) != sk_len { 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)) return nil, errors.New(fmt.Sprintf("nacl.GetSignPubkey() invalid secret key size %d != %d", len(sk), sk_len))
} }
pk_len := C.crypto_sign_publickeybytes() pk_len := C.crypto_sign_publickeybytes()
pkbuff := malloc(pk_len) pkbuff := malloc(pk_len)
defer pkbuff.Free() defer pkbuff.Free()
skbuff := NewBuffer(sk) skbuff := NewBuffer(sk)
defer skbuff.Free() defer skbuff.Free()
//XXX: hack //XXX: hack
res := C.crypto_sign_seed_keypair(pkbuff.uchar(), skbuff.uchar(), skbuff.uchar()) res := C.crypto_sign_seed_keypair(pkbuff.uchar(), skbuff.uchar(), skbuff.uchar())
if res != 0 { if res != 0 {
return nil, errors.New(fmt.Sprintf("nacl.GetSignPubkey() failed to get public key from secret key: %d", res)) return nil, errors.New(fmt.Sprintf("nacl.GetSignPubkey() failed to get public key from secret key: %d", res))
} }
return pkbuff.Bytes(), nil return pkbuff.Bytes(), nil
} }
// make keypair from seed // make keypair from seed
func LoadSignKey(seed []byte) *KeyPair { func LoadSignKey(seed []byte) *KeyPair {
seed_len := C.crypto_sign_seedbytes() seed_len := C.crypto_sign_seedbytes()
if C.size_t(len(seed)) != seed_len { if C.size_t(len(seed)) != seed_len {
return nil panic(fmt.Sprintf("Bad seed length %d bytes", len(seed)))
} }
seedbuff := NewBuffer(seed) seedbuff := NewBuffer(seed)
defer seedbuff.Free() defer seedbuff.Free()
pk_len := C.crypto_sign_publickeybytes() pk_len := C.crypto_sign_publickeybytes()
sk_len := C.crypto_sign_secretkeybytes() sk_len := C.crypto_sign_secretkeybytes()
pkbuff := malloc(pk_len) pkbuff := malloc(pk_len)
skbuff := malloc(sk_len) skbuff := malloc(sk_len)
res := C.crypto_sign_seed_keypair(pkbuff.uchar(), skbuff.uchar(), seedbuff.uchar()) res := C.crypto_sign_seed_keypair(pkbuff.uchar(), skbuff.uchar(), seedbuff.uchar())
if res != 0 { if res != 0 {
pkbuff.Free() pkbuff.Free()
skbuff.Free() skbuff.Free()
return nil return nil
} }
return &KeyPair{pkbuff, skbuff} return &KeyPair{pkbuff, skbuff}
} }
func GenBoxKeypair() *KeyPair { func GenBoxKeypair() *KeyPair {
sk_len := C.crypto_box_secretkeybytes() sk_len := C.crypto_box_secretkeybytes()
sk := malloc(sk_len) sk := malloc(sk_len)
pk_len := C.crypto_box_publickeybytes() pk_len := C.crypto_box_publickeybytes()
pk := malloc(pk_len) pk := malloc(pk_len)
res := C.crypto_box_keypair(pk.uchar(), sk.uchar()) res := C.crypto_box_keypair(pk.uchar(), sk.uchar())
if res == 0 { if res == 0 {
return &KeyPair{pk,sk} return &KeyPair{pk, sk}
} }
pk.Free() pk.Free()
sk.Free() sk.Free()
return nil return nil
} }
// get public key from secret key // get public key from secret key
func GetBoxPubkey(sk []byte) []byte { func GetBoxPubkey(sk []byte) []byte {
sk_len := C.crypto_box_seedbytes() sk_len := C.crypto_box_seedbytes()
if C.size_t(len(sk)) != sk_len { if C.size_t(len(sk)) != sk_len {
return nil return nil
} }
pk_len := C.crypto_box_publickeybytes() pk_len := C.crypto_box_publickeybytes()
pkbuff := malloc(pk_len) pkbuff := malloc(pk_len)
defer pkbuff.Free() defer pkbuff.Free()
skbuff := NewBuffer(sk) skbuff := NewBuffer(sk)
defer skbuff.Free() defer skbuff.Free()
// compute the public key // compute the public key
C.crypto_scalarmult_base(pkbuff.uchar(), skbuff.uchar()) C.crypto_scalarmult_base(pkbuff.uchar(), skbuff.uchar())
return pkbuff.Bytes() return pkbuff.Bytes()
} }
// load keypair from secret key // load keypair from secret key
func LoadBoxKey(sk []byte) *KeyPair { func LoadBoxKey(sk []byte) *KeyPair {
pk := GetBoxPubkey(sk) pk := GetBoxPubkey(sk)
if pk == nil { if pk == nil {
return nil return nil
} }
pkbuff := NewBuffer(pk) pkbuff := NewBuffer(pk)
skbuff := NewBuffer(sk) skbuff := NewBuffer(sk)
return &KeyPair{pkbuff, skbuff} return &KeyPair{pkbuff, skbuff}
} }
// make keypair from seed // make keypair from seed
func SeedBoxKey(seed []byte) *KeyPair { func SeedBoxKey(seed []byte) *KeyPair {
seed_len := C.crypto_box_seedbytes() seed_len := C.crypto_box_seedbytes()
if C.size_t(len(seed)) != seed_len { if C.size_t(len(seed)) != seed_len {
return nil return nil
} }
seedbuff := NewBuffer(seed) seedbuff := NewBuffer(seed)
defer seedbuff.Free() defer seedbuff.Free()
pk_len := C.crypto_box_publickeybytes() pk_len := C.crypto_box_publickeybytes()
sk_len := C.crypto_box_secretkeybytes() sk_len := C.crypto_box_secretkeybytes()
pkbuff := malloc(pk_len) pkbuff := malloc(pk_len)
skbuff := malloc(sk_len) skbuff := malloc(sk_len)
res := C.crypto_box_seed_keypair(pkbuff.uchar(), skbuff.uchar(), seedbuff.uchar()) res := C.crypto_box_seed_keypair(pkbuff.uchar(), skbuff.uchar(), seedbuff.uchar())
if res != 0 { if res != 0 {
pkbuff.Free() pkbuff.Free()
skbuff.Free() skbuff.Free()
return nil return nil
} }
return &KeyPair{pkbuff, skbuff} return &KeyPair{pkbuff, skbuff}
} }
func (self *KeyPair) String() string { func (self *KeyPair) String() string {
return fmt.Sprintf("pk=%s sk=%s", hex.EncodeToString(self.pk.Data()), hex.EncodeToString(self.sk.Data())) return fmt.Sprintf("pk=%s sk=%s", hex.EncodeToString(self.pk.Data()), hex.EncodeToString(self.sk.Data()))
} }
func CryptoSignPublicLen() int { func CryptoSignPublicLen() int {
return int(C.crypto_sign_publickeybytes()) return int(C.crypto_sign_publickeybytes())
} }
func CryptoSignSecretLen() int { func CryptoSignSecretLen() int {
return int(C.crypto_sign_secretkeybytes()) return int(C.crypto_sign_secretkeybytes())
} }
func CryptoSignSeedLen() int { func CryptoSignSeedLen() int {
return int(C.crypto_sign_seedbytes()) return int(C.crypto_sign_seedbytes())
} }

View File

@ -7,39 +7,38 @@ package nacl
import "C" import "C"
import ( import (
"log" "log"
) )
// return how many bytes overhead does CryptoBox have // return how many bytes overhead does CryptoBox have
func CryptoBoxOverhead() int { func CryptoBoxOverhead() int {
return int(C.crypto_box_macbytes()) return int(C.crypto_box_macbytes())
} }
// size of crypto_box public keys // size of crypto_box public keys
func CryptoBoxPubKeySize() int { func CryptoBoxPubKeySize() int {
return int(C.crypto_box_publickeybytes()) return int(C.crypto_box_publickeybytes())
} }
// size of crypto_box private keys // size of crypto_box private keys
func CryptoBoxPrivKeySize() int { func CryptoBoxPrivKeySize() int {
return int(C.crypto_box_secretkeybytes()) return int(C.crypto_box_secretkeybytes())
} }
// size of crypto_sign public keys // size of crypto_sign public keys
func CryptoSignPubKeySize() int { func CryptoSignPubKeySize() int {
return int(C.crypto_sign_publickeybytes()) return int(C.crypto_sign_publickeybytes())
} }
// size of crypto_sign private keys // size of crypto_sign private keys
func CryptoSignPrivKeySize() int { func CryptoSignPrivKeySize() int {
return int(C.crypto_sign_secretkeybytes()) return int(C.crypto_sign_secretkeybytes())
} }
// initialize sodium // initialize sodium
func init() { func init() {
status := C.sodium_init() status := C.sodium_init()
if status == -1 { if status == -1 {
log.Fatalf("failed to initialize libsodium status=%d", status) log.Fatalf("failed to initialize libsodium status=%d", status)
} }
} }

View File

@ -8,17 +8,17 @@ import "C"
func randbytes(size C.size_t) *Buffer { func randbytes(size C.size_t) *Buffer {
buff := malloc(size) buff := malloc(size)
C.randombytes_buf(buff.ptr, size) C.randombytes_buf(buff.ptr, size)
return buff return buff
} }
func RandBytes(size int) []byte { func RandBytes(size int) []byte {
if size > 0 { if size > 0 {
buff := randbytes(C.size_t(size)) buff := randbytes(C.size_t(size))
defer buff.Free() defer buff.Free()
return buff.Bytes() return buff.Bytes()
} }
return nil return nil
} }

View File

@ -6,55 +6,53 @@ package nacl
// #include <sodium.h> // #include <sodium.h>
import "C" import "C"
// sign data detached with secret key sk // sign data detached with secret key sk
func CryptoSignDetached(msg, sk []byte) []byte { func CryptoSignDetached(msg, sk []byte) []byte {
msgbuff := NewBuffer(msg) msgbuff := NewBuffer(msg)
defer msgbuff.Free() defer msgbuff.Free()
skbuff := NewBuffer(sk) skbuff := NewBuffer(sk)
defer skbuff.Free() defer skbuff.Free()
if skbuff.size != C.crypto_sign_bytes() { if skbuff.size != C.crypto_sign_bytes() {
return nil return nil
} }
// allocate the signature buffer // allocate the signature buffer
sig := malloc(C.crypto_sign_bytes()) sig := malloc(C.crypto_sign_bytes())
defer sig.Free() defer sig.Free()
// compute signature // compute signature
siglen := C.ulonglong(0) siglen := C.ulonglong(0)
res := C.crypto_sign_detached(sig.uchar(), &siglen, msgbuff.uchar(), C.ulonglong(msgbuff.size), skbuff.uchar()) 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()) { if res == 0 && siglen == C.ulonglong(C.crypto_sign_bytes()) {
// return copy of signature buffer // return copy of signature buffer
return sig.Bytes() return sig.Bytes()
} }
// failure to sign // failure to sign
return nil return nil
} }
// sign data with secret key sk // sign data with secret key sk
// return detached sig // return detached sig
// this uses crypto_sign instead pf crypto_sign_detached // this uses crypto_sign instead pf crypto_sign_detached
func CryptoSignFucky(msg, sk []byte) []byte { func CryptoSignFucky(msg, sk []byte) []byte {
msgbuff := NewBuffer(msg) msgbuff := NewBuffer(msg)
defer msgbuff.Free() defer msgbuff.Free()
skbuff := NewBuffer(sk) skbuff := NewBuffer(sk)
defer skbuff.Free() defer skbuff.Free()
if skbuff.size != C.crypto_sign_bytes() { if skbuff.size != C.crypto_sign_bytes() {
return nil return nil
} }
// allocate the signed message buffer // allocate the signed message buffer
sig := malloc(C.crypto_sign_bytes()+msgbuff.size) sig := malloc(C.crypto_sign_bytes() + msgbuff.size)
defer sig.Free() defer sig.Free()
// compute signature // compute signature
siglen := C.ulonglong(0) siglen := C.ulonglong(0)
res := C.crypto_sign(sig.uchar(), &siglen, msgbuff.uchar(), C.ulonglong(msgbuff.size), skbuff.uchar()) res := C.crypto_sign(sig.uchar(), &siglen, msgbuff.uchar(), C.ulonglong(msgbuff.size), skbuff.uchar())
if res == 0 { if res == 0 {
// return copy of signature inside the signed message // return copy of signature inside the signed message
offset := int(C.crypto_sign_bytes()) offset := int(C.crypto_sign_bytes())
return sig.Bytes()[:offset] return sig.Bytes()[:offset]
} }
// failure to sign // failure to sign
return nil return nil
} }

View File

@ -1,16 +1,15 @@
package nacl package nacl
import ( import (
"bytes" "bytes"
"errors" "errors"
"io" "io"
"net" "net"
"time" "time"
) )
// TOY encrypted authenticated stream protocol like tls // TOY encrypted authenticated stream protocol like tls
var BadHandshake = errors.New("Bad handshake") var BadHandshake = errors.New("Bad handshake")
var ShortWrite = errors.New("short write") var ShortWrite = errors.New("short write")
var ShortRead = errors.New("short read") var ShortRead = errors.New("short read")
@ -23,106 +22,106 @@ const DefaultMTU = 512
// provides an authenticated encrypted stream // provides an authenticated encrypted stream
// this is a TOY // this is a TOY
type CryptoStream struct { type CryptoStream struct {
// underlying stream to write on // underlying stream to write on
stream io.ReadWriteCloser stream io.ReadWriteCloser
// secret key seed // secret key seed
key *KeyPair key *KeyPair
// public key of who we expect on the other end // public key of who we expect on the other end
remote_pk []byte remote_pk []byte
tx_nonce []byte tx_nonce []byte
rx_nonce []byte rx_nonce []byte
// box size // box size
mtu int mtu int
} }
func (cs *CryptoStream) Close() (err error) { func (cs *CryptoStream) Close() (err error) {
if cs.key != nil { if cs.key != nil {
cs.key.Free() cs.key.Free()
cs.key = nil cs.key = nil
} }
return cs.stream.Close() return cs.stream.Close()
} }
// implements io.Writer // implements io.Writer
func (cs *CryptoStream) Write(data []byte) (n int, err error) { func (cs *CryptoStream) Write(data []byte) (n int, err error) {
// let's split it up // let's split it up
for n < len(data) && err == nil { for n < len(data) && err == nil {
if n + cs.mtu < len(data) { if n+cs.mtu < len(data) {
err = cs.writeSegment(data[n:n+cs.mtu]) err = cs.writeSegment(data[n : n+cs.mtu])
n += cs.mtu n += cs.mtu
} else { } else {
err = cs.writeSegment(data[n:]) err = cs.writeSegment(data[n:])
if err == nil { if err == nil {
n = len(data) n = len(data)
} }
} }
} }
return return
} }
func (cs *CryptoStream) public() (p []byte) { func (cs *CryptoStream) public() (p []byte) {
p = cs.key.Public() p = cs.key.Public()
return return
} }
func (cs *CryptoStream) secret() (s []byte) { func (cs *CryptoStream) secret() (s []byte) {
s = cs.key.Secret() s = cs.key.Secret()
return return
} }
// read 1 segment // read 1 segment
func (cs *CryptoStream) readSegment() (s []byte, err error) { func (cs *CryptoStream) readSegment() (s []byte, err error) {
var stream_read int var stream_read int
var seg []byte var seg []byte
nl := NounceLen() nl := NounceLen()
msg := make([]byte, cs.mtu + nl) msg := make([]byte, cs.mtu+nl)
stream_read, err = cs.stream.Read(msg) stream_read, err = cs.stream.Read(msg)
seg, err = CryptoBoxOpen(msg[:stream_read], cs.rx_nonce, cs.secret(), cs.remote_pk) seg, err = CryptoBoxOpen(msg[:stream_read], cs.rx_nonce, cs.secret(), cs.remote_pk)
if err == nil { if err == nil {
copy(cs.rx_nonce, seg[:nl]) copy(cs.rx_nonce, seg[:nl])
s = seg[nl:] s = seg[nl:]
} }
return return
} }
// write 1 segment encrypted // write 1 segment encrypted
// update nounce // update nounce
func (cs *CryptoStream) writeSegment(data []byte) (err error) { func (cs *CryptoStream) writeSegment(data []byte) (err error) {
var segment []byte var segment []byte
nl := NounceLen() nl := NounceLen()
msg := make([]byte, len(data) + nl) msg := make([]byte, len(data)+nl)
// generate next nounce // generate next nounce
nextNounce := NewBoxNounce() nextNounce := NewBoxNounce()
copy(msg, nextNounce) copy(msg, nextNounce)
copy(msg[nl:], data) copy(msg[nl:], data)
// encrypt segment with current nounce // encrypt segment with current nounce
segment, err = CryptoBox(data, cs.tx_nonce, cs.remote_pk, cs.secret()) segment, err = CryptoBox(data, cs.tx_nonce, cs.remote_pk, cs.secret())
var n int var n int
n, err = cs.stream.Write(segment) n, err = cs.stream.Write(segment)
if n != len(segment) { if n != len(segment) {
// short write? // short write?
err = ShortWrite err = ShortWrite
return return
} }
// update nounce // update nounce
copy(cs.tx_nonce, nextNounce) copy(cs.tx_nonce, nextNounce)
return return
} }
// implements io.Reader // implements io.Reader
func (cs *CryptoStream) Read(data []byte) (n int, err error) { func (cs *CryptoStream) Read(data []byte) (n int, err error) {
var seg []byte var seg []byte
seg, err = cs.readSegment() seg, err = cs.readSegment()
if err == nil { if err == nil {
if len(seg) <= len(data) { if len(seg) <= len(data) {
copy(data, seg) copy(data, seg)
n = len(seg) n = len(seg)
} else { } else {
// too big? // too big?
err = ShortRead err = ShortRead
} }
} }
return return
} }
// version 0 protocol magic // version 0 protocol magic
@ -130,216 +129,214 @@ var protocol_magic = []byte("BENIS|00")
// verify that a handshake is signed right and is in the correct format etc // verify that a handshake is signed right and is in the correct format etc
func verifyHandshake(hs, pk []byte) (valid bool) { func verifyHandshake(hs, pk []byte) (valid bool) {
ml := len(protocol_magic) ml := len(protocol_magic)
// valid handshake? // valid handshake?
if bytes.Equal(hs[0:ml], protocol_magic) { if bytes.Equal(hs[0:ml], protocol_magic) {
// check pk // check pk
pl := CryptoSignPublicLen() pl := CryptoSignPublicLen()
nl := NounceLen() nl := NounceLen()
if bytes.Equal(pk, hs[ml:ml+pl]) { if bytes.Equal(pk, hs[ml:ml+pl]) {
// check signature // check signature
msg := hs[0:ml+pl+nl] msg := hs[0 : ml+pl+nl]
sig := hs[ml+pl+nl:] sig := hs[ml+pl+nl:]
valid = CryptoVerifyFucky(msg, sig, pk) valid = CryptoVerifyFucky(msg, sig, pk)
} }
} }
return return
} }
// get claimed public key from handshake // get claimed public key from handshake
func getPubkey(hs []byte) (pk []byte) { func getPubkey(hs []byte) (pk []byte) {
ml := len(protocol_magic) ml := len(protocol_magic)
pl := CryptoSignPublicLen() pl := CryptoSignPublicLen()
pk = hs[ml:ml+pl] pk = hs[ml : ml+pl]
return return
} }
func (cs *CryptoStream) genHandshake() (d []byte) { func (cs *CryptoStream) genHandshake() (d []byte) {
// protocol magic string version 00 // protocol magic string version 00
// Benis Encrypted Network Information Stream // Benis Encrypted Network Information Stream
// :-DDDDD meme crypto // :-DDDDD meme crypto
d = append(d, protocol_magic...) d = append(d, protocol_magic...)
// our public key // our public key
d = append(d, cs.public()...) d = append(d, cs.public()...)
// nounce // nounce
cs.tx_nonce = NewBoxNounce() cs.tx_nonce = NewBoxNounce()
d = append(d, cs.tx_nonce...) d = append(d, cs.tx_nonce...)
// sign protocol magic string, nounce and pubkey // sign protocol magic string, nounce and pubkey
sig := CryptoSignFucky(d, cs.secret()) sig := CryptoSignFucky(d, cs.secret())
// if sig is nil we'll just die // if sig is nil we'll just die
d = append(d, sig...) d = append(d, sig...)
return return
} }
// extract nounce from handshake // extract nounce from handshake
func getNounce(hs []byte) (n []byte) { func getNounce(hs []byte) (n []byte) {
ml := len(protocol_magic) ml := len(protocol_magic)
pl := CryptoSignPublicLen() pl := CryptoSignPublicLen()
nl := NounceLen() nl := NounceLen()
n = hs[ml+pl:ml+pl+nl] n = hs[ml+pl : ml+pl+nl]
return return
} }
// initiate protocol handshake // initiate protocol handshake
func (cs *CryptoStream) Handshake() (err error) { func (cs *CryptoStream) Handshake() (err error) {
// send them our info // send them our info
hs := cs.genHandshake() hs := cs.genHandshake()
var n int var n int
n, err = cs.stream.Write(hs) n, err = cs.stream.Write(hs)
if n != len(hs) { if n != len(hs) {
err = ShortWrite err = ShortWrite
return return
} }
// read thier info // read thier info
buff := make([]byte, len(hs)) buff := make([]byte, len(hs))
_, err = io.ReadFull(cs.stream, buff) _, err = io.ReadFull(cs.stream, buff)
if cs.remote_pk == nil { if cs.remote_pk == nil {
// inbound // inbound
pk := getPubkey(buff) pk := getPubkey(buff)
cs.remote_pk = make([]byte, len(pk)) cs.remote_pk = make([]byte, len(pk))
copy(cs.remote_pk, pk) copy(cs.remote_pk, pk)
} }
if ! verifyHandshake(buff, cs.remote_pk) { if !verifyHandshake(buff, cs.remote_pk) {
// verification failed // verification failed
err = BadHandshake err = BadHandshake
return return
} }
cs.rx_nonce = make([]byte, NounceLen()) cs.rx_nonce = make([]byte, NounceLen())
copy(cs.rx_nonce, getNounce(buff)) copy(cs.rx_nonce, getNounce(buff))
return return
} }
// create a client // create a client
func Client(stream io.ReadWriteCloser, local_sk, remote_pk []byte) (c *CryptoStream) { func Client(stream io.ReadWriteCloser, local_sk, remote_pk []byte) (c *CryptoStream) {
c = &CryptoStream{ c = &CryptoStream{
stream: stream, stream: stream,
mtu: DefaultMTU, mtu: DefaultMTU,
} }
c.remote_pk = make([]byte, len(remote_pk)) c.remote_pk = make([]byte, len(remote_pk))
copy(c.remote_pk, remote_pk) copy(c.remote_pk, remote_pk)
c.key = LoadSignKey(local_sk) c.key = LoadSignKey(local_sk)
if c.key == nil { if c.key == nil {
return nil return nil
} }
return c return c
} }
type CryptoConn struct { type CryptoConn struct {
stream *CryptoStream stream *CryptoStream
conn net.Conn conn net.Conn
} }
func (cc *CryptoConn) Close() (err error) { func (cc *CryptoConn) Close() (err error) {
err = cc.stream.Close() err = cc.stream.Close()
return return
} }
func (cc *CryptoConn) Write(d []byte) (n int, err error) { func (cc *CryptoConn) Write(d []byte) (n int, err error) {
return cc.stream.Write(d) return cc.stream.Write(d)
} }
func (cc *CryptoConn) Read(d []byte) (n int, err error) { func (cc *CryptoConn) Read(d []byte) (n int, err error) {
return cc.stream.Read(d) return cc.stream.Read(d)
} }
func (cc *CryptoConn) LocalAddr() net.Addr { func (cc *CryptoConn) LocalAddr() net.Addr {
return cc.conn.LocalAddr() return cc.conn.LocalAddr()
} }
func (cc *CryptoConn) RemoteAddr() net.Addr { func (cc *CryptoConn) RemoteAddr() net.Addr {
return cc.conn.RemoteAddr() return cc.conn.RemoteAddr()
} }
func (cc *CryptoConn) SetDeadline(t time.Time) (err error) { func (cc *CryptoConn) SetDeadline(t time.Time) (err error) {
return cc.conn.SetDeadline(t) return cc.conn.SetDeadline(t)
} }
func (cc *CryptoConn) SetReadDeadline(t time.Time) (err error) { func (cc *CryptoConn) SetReadDeadline(t time.Time) (err error) {
return cc.conn.SetReadDeadline(t) return cc.conn.SetReadDeadline(t)
} }
func (cc *CryptoConn) SetWriteDeadline(t time.Time) (err error) { func (cc *CryptoConn) SetWriteDeadline(t time.Time) (err error) {
return cc.conn.SetWriteDeadline(t) return cc.conn.SetWriteDeadline(t)
} }
type CryptoListener struct { type CryptoListener struct {
l net.Listener l net.Listener
handshake chan net.Conn handshake chan net.Conn
accepted chan *CryptoConn accepted chan *CryptoConn
trust func(pk []byte) bool trust func(pk []byte) bool
key *KeyPair key *KeyPair
} }
func (cl *CryptoListener) Close() (err error) { func (cl *CryptoListener) Close() (err error) {
err = cl.l.Close() err = cl.l.Close()
close(cl.accepted) close(cl.accepted)
close(cl.handshake) close(cl.handshake)
cl.key.Free() cl.key.Free()
cl.key = nil cl.key = nil
return return
} }
func (cl *CryptoListener) acceptInbound() { func (cl *CryptoListener) acceptInbound() {
for { for {
c, err := cl.l.Accept() c, err := cl.l.Accept()
if err == nil { if err == nil {
cl.handshake <- c cl.handshake <- c
} else { } else {
return return
} }
} }
} }
func (cl *CryptoListener) runChans() { func (cl *CryptoListener) runChans() {
for { for {
select { select {
case c := <- cl.handshake: case c := <-cl.handshake:
go func(){ go func() {
s := &CryptoStream{ s := &CryptoStream{
stream: c, stream: c,
mtu: DefaultMTU, mtu: DefaultMTU,
key: cl.key, key: cl.key,
} }
err := s.Handshake() err := s.Handshake()
if err == nil { if err == nil {
// we gud handshake was okay // we gud handshake was okay
if cl.trust(s.remote_pk) { if cl.trust(s.remote_pk) {
// the key is trusted okay // the key is trusted okay
cl.accepted <- &CryptoConn{stream: s, conn: c} cl.accepted <- &CryptoConn{stream: s, conn: c}
} else { } else {
// not trusted, close connection // not trusted, close connection
s.Close() s.Close()
} }
} }
}() }()
} }
} }
} }
// accept inbound authenticated and trusted connections // accept inbound authenticated and trusted connections
func (cl *CryptoListener) Accept() (c net.Conn, err error) { func (cl *CryptoListener) Accept() (c net.Conn, err error) {
var ok bool var ok bool
c, ok = <- cl.accepted c, ok = <-cl.accepted
if ! ok { if !ok {
err = Closed err = Closed
} }
return return
} }
// create a listener // create a listener
func Server(l net.Listener, local_sk []byte, trust func(pk []byte) bool) (s *CryptoListener) { func Server(l net.Listener, local_sk []byte, trust func(pk []byte) bool) (s *CryptoListener) {
s = &CryptoListener{ s = &CryptoListener{
l: l, l: l,
trust: trust, trust: trust,
handshake: make(chan net.Conn), handshake: make(chan net.Conn),
accepted: make(chan *CryptoConn), accepted: make(chan *CryptoConn),
} }
s.key = LoadSignKey(local_sk) s.key = LoadSignKey(local_sk)
go s.runChans() go s.runChans()
go s.acceptInbound() go s.acceptInbound()
return return
} }

View File

@ -6,49 +6,48 @@ package nacl
// #include <sodium.h> // #include <sodium.h>
import "C" import "C"
// verify a fucky detached sig // verify a fucky detached sig
func CryptoVerifyFucky(msg, sig, pk []byte) bool { func CryptoVerifyFucky(msg, sig, pk []byte) bool {
var smsg []byte var smsg []byte
smsg = append(smsg, sig...) smsg = append(smsg, sig...)
smsg = append(smsg, msg...) smsg = append(smsg, msg...)
return CryptoVerify(smsg, pk) return CryptoVerify(smsg, pk)
} }
// verify a signed message // verify a signed message
func CryptoVerify(smsg, pk []byte) bool { func CryptoVerify(smsg, pk []byte) bool {
smsg_buff := NewBuffer(smsg) smsg_buff := NewBuffer(smsg)
defer smsg_buff.Free() defer smsg_buff.Free()
pk_buff := NewBuffer(pk) pk_buff := NewBuffer(pk)
defer pk_buff.Free() defer pk_buff.Free()
if pk_buff.size != C.crypto_sign_publickeybytes() { if pk_buff.size != C.crypto_sign_publickeybytes() {
return false return false
} }
mlen := C.ulonglong(0) mlen := C.ulonglong(0)
msg := malloc(C.size_t(len(smsg))) msg := malloc(C.size_t(len(smsg)))
defer msg.Free() defer msg.Free()
smlen := C.ulonglong(smsg_buff.size) smlen := C.ulonglong(smsg_buff.size)
return C.crypto_sign_open(msg.uchar(), &mlen, smsg_buff.uchar(), smlen, pk_buff.uchar()) != -1 return C.crypto_sign_open(msg.uchar(), &mlen, smsg_buff.uchar(), smlen, pk_buff.uchar()) != -1
} }
// verfiy a detached signature // verfiy a detached signature
// return true on valid otherwise false // return true on valid otherwise false
func CryptoVerifyDetached(msg, sig, pk []byte) bool { func CryptoVerifyDetached(msg, sig, pk []byte) bool {
msg_buff := NewBuffer(msg) msg_buff := NewBuffer(msg)
defer msg_buff.Free() defer msg_buff.Free()
sig_buff := NewBuffer(sig) sig_buff := NewBuffer(sig)
defer sig_buff.Free() defer sig_buff.Free()
pk_buff := NewBuffer(pk) pk_buff := NewBuffer(pk)
defer pk_buff.Free() defer pk_buff.Free()
if pk_buff.size != C.crypto_sign_publickeybytes() { if pk_buff.size != C.crypto_sign_publickeybytes() {
return false return false
} }
// invalid sig size // invalid sig size
if sig_buff.size != C.crypto_sign_bytes() { if sig_buff.size != C.crypto_sign_bytes() {
return false return false
} }
return C.crypto_sign_verify_detached(sig_buff.uchar(), msg_buff.uchar(), C.ulonglong(len(msg)), pk_buff.uchar()) == 0 return C.crypto_sign_verify_detached(sig_buff.uchar(), msg_buff.uchar(), C.ulonglong(len(msg)), pk_buff.uchar()) == 0
} }