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 (
"errors"
"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()
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
}
// 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()
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
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()
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
}
// 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()
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
// 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())
return RandBytes(NounceLen())
}
// length of a nounce
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 (
"encoding/hex"
"reflect"
"unsafe"
"encoding/hex"
"reflect"
"unsafe"
)
// wrapper arround malloc/free
type Buffer struct {
ptr unsafe.Pointer;
length C.int;
size C.size_t;
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
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
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
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)
return C.deref_uchar(self.ptr)
}
func (self *Buffer) Length() int {
return int(self.length)
return int(self.length)
}
// get immutable byte slice
func (self *Buffer) Bytes() []byte {
buff := make([]byte, self.Length())
copy(buff, self.Data())
return buff
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))
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())
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)
C.sodium_memzero(self.ptr, self.size)
C.free(self.ptr)
}

View File

@ -7,174 +7,172 @@ package nacl
import "C"
import (
"encoding/hex"
"errors"
"fmt"
"encoding/hex"
"errors"
"fmt"
)
type KeyPair struct {
pk *Buffer
sk *Buffer
pk *Buffer
sk *Buffer
}
// free this keypair from memory
func (self *KeyPair) Free() {
self.pk.Free()
self.sk.Free()
self.pk.Free()
self.sk.Free()
}
func (self *KeyPair) Secret() []byte {
return self.sk.Bytes()
return self.sk.Bytes()
}
func (self *KeyPair) Public() []byte {
return self.pk.Bytes()
return self.pk.Bytes()
}
func (self *KeyPair) Seed() []byte {
seed_len := C.crypto_sign_seedbytes()
return self.sk.Bytes()[:seed_len]
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
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))
}
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()
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())
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))
}
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
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}
seed_len := C.crypto_sign_seedbytes()
if C.size_t(len(seed)) != seed_len {
panic(fmt.Sprintf("Bad seed length %d bytes", len(seed)))
}
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
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
}
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()
pk_len := C.crypto_box_publickeybytes()
pkbuff := malloc(pk_len)
defer pkbuff.Free()
skbuff := NewBuffer(sk)
defer skbuff.Free()
skbuff := NewBuffer(sk)
defer skbuff.Free()
// compute the public key
C.crypto_scalarmult_base(pkbuff.uchar(), skbuff.uchar())
// compute the public key
C.crypto_scalarmult_base(pkbuff.uchar(), skbuff.uchar())
return pkbuff.Bytes()
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}
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}
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()))
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())
return int(C.crypto_sign_publickeybytes())
}
func CryptoSignSecretLen() int {
return int(C.crypto_sign_secretkeybytes())
return int(C.crypto_sign_secretkeybytes())
}
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 (
"log"
"log"
)
// return how many bytes overhead does CryptoBox have
func CryptoBoxOverhead() int {
return int(C.crypto_box_macbytes())
return int(C.crypto_box_macbytes())
}
// size of crypto_box public keys
func CryptoBoxPubKeySize() int {
return int(C.crypto_box_publickeybytes())
return int(C.crypto_box_publickeybytes())
}
// size of crypto_box private keys
func CryptoBoxPrivKeySize() int {
return int(C.crypto_box_secretkeybytes())
return int(C.crypto_box_secretkeybytes())
}
// size of crypto_sign public keys
func CryptoSignPubKeySize() int {
return int(C.crypto_sign_publickeybytes())
return int(C.crypto_sign_publickeybytes())
}
// size of crypto_sign private keys
func CryptoSignPrivKeySize() int {
return int(C.crypto_sign_secretkeybytes())
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)
}
status := C.sodium_init()
if status == -1 {
log.Fatalf("failed to initialize libsodium status=%d", status)
}
}

View File

@ -8,17 +8,17 @@ import "C"
func randbytes(size C.size_t) *Buffer {
buff := malloc(size)
C.randombytes_buf(buff.ptr, size)
return buff
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
if size > 0 {
buff := randbytes(C.size_t(size))
defer buff.Free()
return buff.Bytes()
}
return nil
}

View File

@ -6,55 +6,53 @@ package nacl
// #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
}
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
// 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
}
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
// 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
}

View File

@ -1,16 +1,15 @@
package nacl
import (
"bytes"
"errors"
"io"
"net"
"time"
"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")
@ -23,106 +22,106 @@ const DefaultMTU = 512
// 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
// 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()
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
// 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
p = cs.key.Public()
return
}
func (cs *CryptoStream) secret() (s []byte) {
s = cs.key.Secret()
return
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
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
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
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
@ -130,216 +129,214 @@ 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
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
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
// 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
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)
// 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 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
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
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
stream *CryptoStream
conn net.Conn
}
func (cc *CryptoConn) Close() (err error) {
err = cc.stream.Close()
return
err = cc.stream.Close()
return
}
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) {
return cc.stream.Read(d)
return cc.stream.Read(d)
}
func (cc *CryptoConn) LocalAddr() net.Addr {
return cc.conn.LocalAddr()
return cc.conn.LocalAddr()
}
func (cc *CryptoConn) RemoteAddr() net.Addr {
return cc.conn.RemoteAddr()
return cc.conn.RemoteAddr()
}
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) {
return cc.conn.SetReadDeadline(t)
return cc.conn.SetReadDeadline(t)
}
func (cc *CryptoConn) SetWriteDeadline(t time.Time) (err error) {
return cc.conn.SetWriteDeadline(t)
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
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
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
}
}
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()
}
}
}()
}
}
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
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
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
}

View File

@ -6,49 +6,48 @@ package nacl
// #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)
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()
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
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()
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
}
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
// 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
}