mirror of
https://github.com/go-i2p/go-i2p.git
synced 2025-07-04 05:26:51 -04:00
testing and improvements to the common data structures
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/bounce-chat/go-i2p/lib/crypto"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -28,73 +28,46 @@ const (
|
||||
KEYCERT_CRYPTO_ELG = iota
|
||||
)
|
||||
|
||||
// used to append data to existing data structures
|
||||
type Certificate []byte
|
||||
|
||||
// return the type of this certificate
|
||||
func (c Certificate) Type() byte {
|
||||
return c[0]
|
||||
func (certificate Certificate) Type() byte {
|
||||
return certificate[0]
|
||||
}
|
||||
|
||||
// get the length of the data in this certificate
|
||||
// return -1 if the size of the certificate is invalid
|
||||
func (c Certificate) Len() int {
|
||||
if len(c) <= 2 {
|
||||
// invalid size
|
||||
return -1
|
||||
func (certificate Certificate) Length() (int, error) {
|
||||
if len(certificate) < 3 {
|
||||
// log
|
||||
return 0, errors.New("error parsing certificate length: certificate is too short")
|
||||
}
|
||||
return Integer(c[1:3])
|
||||
}
|
||||
|
||||
// get the data for this certificate or null if none exists
|
||||
func (c Certificate) Data() (d []byte) {
|
||||
l := c.Len()
|
||||
if l > 0 && len(c) <= 3+l {
|
||||
d = c[3 : 3+l]
|
||||
length := Integer(certificate[1:3])
|
||||
inferred_len := length + 3
|
||||
cert_len := len(certificate)
|
||||
if inferred_len > cert_len {
|
||||
// log
|
||||
return length, errors.New("certificate parsing warning: certificate data is shorter than specified by length")
|
||||
} else if cert_len > inferred_len {
|
||||
//log
|
||||
return length, errors.New("certificate parsing warning: certificate contains data beyond length")
|
||||
}
|
||||
return
|
||||
return length, nil
|
||||
}
|
||||
|
||||
// a Certificate of type KEY
|
||||
type KeyCert []byte
|
||||
|
||||
func (c KeyCert) Type() byte {
|
||||
return Certificate(c).Type()
|
||||
}
|
||||
|
||||
func (c KeyCert) Data() []byte {
|
||||
return Certificate(c).Data()
|
||||
}
|
||||
|
||||
// get the signing public key from this key cert
|
||||
func (c KeyCert) SigningPublicKey() (k crypto.SigningPublicKey) {
|
||||
data := c.Data()
|
||||
ktype := Integer(data[:2])
|
||||
// set data to be the key data now
|
||||
data = data[4:]
|
||||
// determine the key type
|
||||
if ktype == KEYCERT_SIGN_DSA_SHA1 {
|
||||
var pk crypto.DSAPublicKey
|
||||
copy(pk[:], data[:pk.Len()])
|
||||
k = pk
|
||||
} else if ktype == KEYCERT_SIGN_P256 {
|
||||
var pk crypto.ECP256PublicKey
|
||||
copy(pk[:], data[:pk.Len()])
|
||||
k = pk
|
||||
} else if ktype == KEYCERT_SIGN_P384 {
|
||||
var pk crypto.ECP384PublicKey
|
||||
copy(pk[:], data[:pk.Len()])
|
||||
k = pk
|
||||
} else if ktype == KEYCERT_SIGN_P521 {
|
||||
var pk crypto.ECP521PublicKey
|
||||
copy(pk[:], data[:pk.Len()])
|
||||
k = pk
|
||||
func (certificate Certificate) Data() ([]byte, error) {
|
||||
length, err := certificate.Length()
|
||||
if err != nil {
|
||||
switch err.Error() {
|
||||
case "error parsing certificate length: certificate is too short":
|
||||
return make([]byte, 0), err
|
||||
case "certificate parsing warning: certificate data is shorter than specified by length":
|
||||
return certificate[3:], err
|
||||
case "certificate parsing warning: certificate contains data beyond length":
|
||||
return certificate[3 : length+3], err
|
||||
}
|
||||
}
|
||||
// TODO: rsa/eddsa
|
||||
return
|
||||
return certificate[3:], nil
|
||||
}
|
||||
|
||||
func (c Certificate) signatureSize() int {
|
||||
func (certificate Certificate) SignatureSize() int {
|
||||
sizes := map[int]int{
|
||||
KEYCERT_SIGN_DSA_SHA1: 40,
|
||||
KEYCERT_SIGN_P256: 64,
|
||||
@ -105,5 +78,21 @@ func (c Certificate) signatureSize() int {
|
||||
KEYCERT_SIGN_RSA4096: 512,
|
||||
KEYCERT_SIGN_ED25519: 64,
|
||||
}
|
||||
return sizes[int(c.Type())]
|
||||
return sizes[int(certificate.Type())]
|
||||
}
|
||||
|
||||
func ReadCertificate(data []byte) (Certificate, []byte, error) {
|
||||
certificate := Certificate(data)
|
||||
length, err := certificate.Length()
|
||||
if err != nil {
|
||||
switch err.Error() {
|
||||
case "error parsing certificate length: certificate is too short":
|
||||
return Certificate{}, make([]byte, 0), err
|
||||
case "certificate parsing warning: certificate data is shorter than specified by length":
|
||||
return certificate, make([]byte, 0), err
|
||||
case "certificate parsing warning: certificate contains data beyond length":
|
||||
return Certificate(certificate[:length+3]), certificate[length+3:], nil
|
||||
}
|
||||
}
|
||||
return certificate, make([]byte, 0), nil
|
||||
}
|
||||
|
160
lib/common/certificate_test.go
Normal file
160
lib/common/certificate_test.go
Normal file
@ -0,0 +1,160 @@
|
||||
package common
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCertificateTypeIsFirstByte(t *testing.T) {
|
||||
bytes := []byte{0x03, 0x00, 0x00}
|
||||
certificate := Certificate(bytes)
|
||||
if certificate.Type() != 0x03 {
|
||||
t.Fatal("certificate.Type() is not first byte")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertificateLengthCorrect(t *testing.T) {
|
||||
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff}
|
||||
certificate := Certificate(bytes)
|
||||
cert_len, err := certificate.Length()
|
||||
if cert_len != 2 {
|
||||
t.Fatal("certificate.Length() is not correct:", cert_len)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal("certificate.Length() returned err", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertificateLengthErrWhenTooShort(t *testing.T) {
|
||||
bytes := []byte{0x03, 0x00}
|
||||
certificate := Certificate(bytes)
|
||||
cert_len, err := certificate.Length()
|
||||
if cert_len != 0 {
|
||||
t.Fatal("certificate.Length() is not correct:", cert_len)
|
||||
}
|
||||
if err == nil || err.Error() != "error parsing certificate length: certificate is too short" {
|
||||
t.Fatal("certificate.Length() did not return correct err:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertificateLengthErrWhenDataTooShort(t *testing.T) {
|
||||
bytes := []byte{0x03, 0x00, 0x02, 0xff}
|
||||
certificate := Certificate(bytes)
|
||||
cert_len, err := certificate.Length()
|
||||
if cert_len != 2 {
|
||||
t.Fatal("certificate.Length() is not correct:", cert_len)
|
||||
}
|
||||
if err == nil || err.Error() != "certificate parsing warning: certificate data is shorter than specified by length" {
|
||||
t.Fatal("certificate.Length() did not return correct err:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertificateDataWhenCorrectSize(t *testing.T) {
|
||||
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff}
|
||||
certificate := Certificate(bytes)
|
||||
cert_data, err := certificate.Data()
|
||||
if err != nil {
|
||||
t.Fatal("certificate.Data() returned error", err)
|
||||
}
|
||||
cert_len := len(cert_data)
|
||||
if cert_len != 2 {
|
||||
t.Fatal("certificate.Data() did not return correct length:", cert_len)
|
||||
}
|
||||
if cert_data[0] != 0xff || cert_data[1] != 0xff {
|
||||
t.Fatal("certificate.Data() returned incorrect data")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertificateDataWhenTooLong(t *testing.T) {
|
||||
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff, 0xaa, 0xaa}
|
||||
certificate := Certificate(bytes)
|
||||
cert_data, err := certificate.Data()
|
||||
if err == nil || err.Error() != "certificate parsing warning: certificate contains data beyond length" {
|
||||
t.Fatal("certificate.Data() returned wrong error:", err)
|
||||
}
|
||||
cert_len := len(cert_data)
|
||||
if cert_len != 2 {
|
||||
t.Fatal("certificate.Data() did not return correct length:", cert_len)
|
||||
}
|
||||
if cert_data[0] != 0xff || cert_data[1] != 0xff {
|
||||
t.Fatal("certificate.Data() returned incorrect data")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertificateDataWhenTooShort(t *testing.T) {
|
||||
bytes := []byte{0x03, 0x00, 0x02, 0xff}
|
||||
certificate := Certificate(bytes)
|
||||
cert_data, err := certificate.Data()
|
||||
if err == nil || err.Error() != "certificate parsing warning: certificate data is shorter than specified by length" {
|
||||
t.Fatal("certificate.Data() did not return correct error:", err)
|
||||
}
|
||||
cert_len := len(cert_data)
|
||||
if cert_len != 1 {
|
||||
t.Fatal("certificate.Data() did not return correct length when too short:", cert_len)
|
||||
}
|
||||
if cert_data[0] != 0xff {
|
||||
t.Fatal("certificate.Data() returned incorrect data")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestReadCertificateWithCorrectData(t *testing.T) {
|
||||
bytes := []byte{0x00, 0x00, 0x02, 0xff, 0xff}
|
||||
cert, remainder, err := ReadCertificate(bytes)
|
||||
cert_len := len(cert)
|
||||
if cert_len != 5 {
|
||||
t.Fatal("ReadCertificate() did not return correct certificate length:", cert_len)
|
||||
}
|
||||
if len(remainder) != 0 {
|
||||
t.Fatal("ReadCertificate() returned a remainder incorrectly:", len(remainder))
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal("ReadCertificate returned error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadCertificateWithDataTooShort(t *testing.T) {
|
||||
bytes := []byte{0x00, 0x00, 0x02, 0xff}
|
||||
cert, remainder, err := ReadCertificate(bytes)
|
||||
cert_len := len(cert)
|
||||
if cert_len != 4 {
|
||||
t.Fatal("ReadCertificate() did not return correct certificate length:", cert_len)
|
||||
}
|
||||
if len(remainder) != 0 {
|
||||
t.Fatal("ReadCertificate() returned a remainder incorrectly when data too short:", len(remainder))
|
||||
}
|
||||
if err == nil || err.Error() != "certificate parsing warning: certificate data is shorter than specified by length" {
|
||||
t.Fatal("ReadCertificate returned incorrect error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadCertificateWithRemainder(t *testing.T) {
|
||||
bytes := []byte{0x00, 0x00, 0x02, 0xff, 0xff, 0x00}
|
||||
cert, remainder, err := ReadCertificate(bytes)
|
||||
cert_len := len(cert)
|
||||
if cert_len != 5 {
|
||||
t.Fatal("ReadCertificate() did not return correct certificate length:", cert_len)
|
||||
}
|
||||
if len(remainder) != 1 {
|
||||
t.Fatal("ReadCertificate() returned a remainder incorrectly:", len(remainder))
|
||||
}
|
||||
if remainder[0] != 0x00 {
|
||||
t.Fatal("ReadCertificate() did not return correct remainder value")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal("ReadCertificate returned error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadCertificateWithInvalidLength(t *testing.T) {
|
||||
bytes := []byte{0x00, 0x00}
|
||||
cert, remainder, err := ReadCertificate(bytes)
|
||||
cert_len := len(cert)
|
||||
if cert_len != 0 {
|
||||
t.Fatal("ReadCertificate() did not return 0 length certificate with invalid length:", cert_len)
|
||||
}
|
||||
remainder_len := len(remainder)
|
||||
if remainder_len != 0 {
|
||||
t.Fatal("ReadCertificate() did not return 0 length remainder with invalid length:", remainder_len)
|
||||
}
|
||||
if err == nil || err.Error() != "error parsing certificate length: certificate is too short" {
|
||||
t.Fatal("ReadCertificate() returned an incorrect error with invalid length:", err)
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
package common
|
||||
|
||||
// the sha256 of some datastructure
|
||||
type IdentHash [32]byte
|
@ -7,53 +7,26 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// a network endpoint inside i2p
|
||||
// effectively a public key blob
|
||||
type Destination []byte
|
||||
|
||||
// obtain public elgamal key
|
||||
func (dest Destination) PublicKey() (k crypto.PublicEncryptionKey) {
|
||||
cert := dest.Certificate()
|
||||
if cert.Type() == CERT_KEY {
|
||||
// TODO(psi): check for key cert and included encryption key
|
||||
} else {
|
||||
var ek crypto.ElgPublicKey
|
||||
copy(ek[:], dest[:256])
|
||||
k = ek
|
||||
}
|
||||
return
|
||||
func (destination Destination) PublicKey() (key crypto.ElgPublicKey) {
|
||||
return KeysAndCert(destination).PublicKey()
|
||||
}
|
||||
|
||||
// obtain destination certificate
|
||||
func (dest Destination) Certificate() Certificate {
|
||||
return Certificate(dest[128+256:])
|
||||
func (destination Destination) SigningPublicKey() (key crypto.SigningPublicKey) {
|
||||
return KeysAndCert(destination).SigningPublicKey()
|
||||
}
|
||||
|
||||
// gets this destination's signing key
|
||||
// if there is a keycert in this destination the signing key in there is used
|
||||
func (dest Destination) SigningPublicKey() (k crypto.SigningPublicKey) {
|
||||
cert := dest.Certificate()
|
||||
if cert.Type() == CERT_KEY {
|
||||
// we have a key certificate
|
||||
// extract the signing key from the key cert
|
||||
k = KeyCert(cert).SigningPublicKey()
|
||||
} else {
|
||||
var pk crypto.DSAPublicKey
|
||||
copy(pk[:], dest[256:256+128])
|
||||
k = pk
|
||||
}
|
||||
return
|
||||
func (destination Destination) Certificate() (cert Certificate) {
|
||||
return KeysAndCert(destination).Certificate()
|
||||
}
|
||||
|
||||
// return the .b32.i2p address
|
||||
func (dest Destination) Base32Address() (str string) {
|
||||
h := crypto.SHA256(dest)
|
||||
str = strings.Trim(base32.EncodeToString(h[:]), "=")
|
||||
str += ".b32.i2p"
|
||||
return
|
||||
func (destination Destination) Base32Address() string {
|
||||
hash := crypto.SHA256(destination)
|
||||
str := strings.Trim(base32.EncodeToString(hash[:]), "=")
|
||||
return str + ".b32.i2p"
|
||||
}
|
||||
|
||||
func (dest Destination) Base64() (str string) {
|
||||
str = base64.EncodeToString(dest)
|
||||
return
|
||||
func (destination Destination) Base64() string {
|
||||
return base64.EncodeToString(destination)
|
||||
}
|
||||
|
3
lib/common/hash.go
Normal file
3
lib/common/hash.go
Normal file
@ -0,0 +1,3 @@
|
||||
package common
|
||||
|
||||
type Hash [32]byte
|
46
lib/common/key_certificate.go
Normal file
46
lib/common/key_certificate.go
Normal file
@ -0,0 +1,46 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/bounce-chat/go-i2p/lib/crypto"
|
||||
)
|
||||
|
||||
type KeyCertificate []byte
|
||||
|
||||
func (key_certificate KeyCertificate) Type() byte {
|
||||
return Certificate(key_certificate).Type()
|
||||
}
|
||||
|
||||
func (key_certificate KeyCertificate) Data() ([]byte, error) {
|
||||
return Certificate(key_certificate).Data()
|
||||
}
|
||||
|
||||
// get the signing public key from this key cert
|
||||
func (key_certificate KeyCertificate) SigningPublicKey() (k crypto.SigningPublicKey) {
|
||||
data, err := key_certificate.Data()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ktype := Integer(data[:2])
|
||||
// set data to be the key data now
|
||||
data = data[4:]
|
||||
// determine the key type
|
||||
if ktype == KEYCERT_SIGN_DSA_SHA1 {
|
||||
var pk crypto.DSAPublicKey
|
||||
copy(pk[:], data[:pk.Len()])
|
||||
k = pk
|
||||
} else if ktype == KEYCERT_SIGN_P256 {
|
||||
var pk crypto.ECP256PublicKey
|
||||
copy(pk[:], data[:pk.Len()])
|
||||
k = pk
|
||||
} else if ktype == KEYCERT_SIGN_P384 {
|
||||
var pk crypto.ECP384PublicKey
|
||||
copy(pk[:], data[:pk.Len()])
|
||||
k = pk
|
||||
} else if ktype == KEYCERT_SIGN_P521 {
|
||||
var pk crypto.ECP521PublicKey
|
||||
copy(pk[:], data[:pk.Len()])
|
||||
k = pk
|
||||
}
|
||||
// TODO: rsa/eddsa
|
||||
return
|
||||
}
|
1
lib/common/key_certificate_test.go
Normal file
1
lib/common/key_certificate_test.go
Normal file
@ -0,0 +1 @@
|
||||
package common
|
@ -1,7 +1,43 @@
|
||||
package common
|
||||
|
||||
//
|
||||
// Both Destination and RouterIdentity share the same structure
|
||||
// https://geti2p.net/en/docs/spec/common-structures#struct_KeysAndCert
|
||||
// Perhaps we can avoid repeating ourselves being using commong functions
|
||||
//
|
||||
import (
|
||||
"github.com/bounce-chat/go-i2p/lib/crypto"
|
||||
)
|
||||
|
||||
type KeysAndCert []byte
|
||||
|
||||
func (keys_and_cert KeysAndCert) PublicKey() (key crypto.ElgPublicKey) {
|
||||
if len(keys_and_cert) < 387 {
|
||||
|
||||
}
|
||||
copy(keys_and_cert[:256], key[:])
|
||||
return
|
||||
}
|
||||
|
||||
func (keys_and_cert KeysAndCert) SigningPublicKey() (key crypto.SigningPublicKey) {
|
||||
cert := keys_and_cert.Certificate()
|
||||
if cert.Type() == CERT_KEY {
|
||||
key = KeyCertificate(cert).SigningPublicKey()
|
||||
} else {
|
||||
var pk crypto.DSAPublicKey
|
||||
copy(pk[:], keys_and_cert[256:256+128])
|
||||
key = pk
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (keys_and_cert KeysAndCert) Certificate() (cert Certificate) {
|
||||
copy(keys_and_cert[256+128:], cert)
|
||||
return
|
||||
}
|
||||
|
||||
func ReadKeysAndCert(data []byte) (KeysAndCert, []byte, error) {
|
||||
var keys_and_cert KeysAndCert
|
||||
copy(data[:387], keys_and_cert)
|
||||
n, err := keys_and_cert.Certificate().Length()
|
||||
if err != nil {
|
||||
return keys_and_cert, data, err
|
||||
}
|
||||
keys_and_cert = append(keys_and_cert, data[387:n]...)
|
||||
return keys_and_cert, data[387+n:], nil
|
||||
}
|
||||
|
1
lib/common/keys_and_cert_test.go
Normal file
1
lib/common/keys_and_cert_test.go
Normal file
@ -0,0 +1 @@
|
||||
package common
|
@ -10,7 +10,7 @@ const (
|
||||
|
||||
type Lease [LEASE_SIZE]byte
|
||||
|
||||
func (lease Lease) TunnelGateway() (h IdentHash) {
|
||||
func (lease Lease) TunnelGateway() (h Hash) {
|
||||
copy(lease[:32], h[:])
|
||||
return
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ func (lease_set LeaseSet) Signature() []byte {
|
||||
sig_size := lease_set.
|
||||
Destination().
|
||||
Certificate().
|
||||
signatureSize()
|
||||
SignatureSize()
|
||||
return lease_set[data_end : data_end+sig_size]
|
||||
}
|
||||
|
||||
|
1
lib/common/lease_set_test.go
Normal file
1
lib/common/lease_set_test.go
Normal file
@ -0,0 +1 @@
|
||||
package common
|
1
lib/common/lease_test.go
Normal file
1
lib/common/lease_test.go
Normal file
@ -0,0 +1 @@
|
||||
package common
|
@ -1,41 +1,49 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"strings"
|
||||
// "encoding/binary"
|
||||
// "strings"
|
||||
)
|
||||
|
||||
type Mapping []byte
|
||||
|
||||
func (mapping Mapping) ToMap() map[string]string {
|
||||
gomap := make(map[string]string)
|
||||
kv_store := string(mapping[2:])
|
||||
pairs := strings.Split(kv_store, ";")
|
||||
for _, pair := range pairs {
|
||||
values := strings.Split(pair, "=")
|
||||
if len(values) != 2 {
|
||||
continue
|
||||
}
|
||||
gomap[values[0]] = values[1]
|
||||
}
|
||||
return gomap
|
||||
func (mapping Mapping) Values() [][2][]byte {
|
||||
return make([][2][]byte, 0)
|
||||
}
|
||||
|
||||
func MappingFromMap(gomap map[string]string) Mapping {
|
||||
kv_store := make([]byte, 0)
|
||||
for k, v := range gomap {
|
||||
key_bytes := []byte(k)
|
||||
key_bytes = append(key_bytes, 0x3d)
|
||||
value_bytes := []byte(v)
|
||||
value_bytes = append(value_bytes, 0x3b)
|
||||
kv_store = append(kv_store, key_bytes...)
|
||||
kv_store = append(kv_store, value_bytes...)
|
||||
}
|
||||
kv_size := uint16(len(kv_store))
|
||||
var size [2]byte
|
||||
binary.BigEndian.PutUint16(size[:], kv_size)
|
||||
mapping := Mapping{}
|
||||
mapping = append(mapping, size[:]...)
|
||||
mapping = append(mapping, kv_store...)
|
||||
return mapping
|
||||
func ValuesToMapping(values [][2][]byte) Mapping {
|
||||
return Mapping{}
|
||||
}
|
||||
|
||||
//func (mapping Mapping) ToMap() map[string]string {
|
||||
// gomap := make(map[string]string)
|
||||
// kv_store := string(mapping[2:])
|
||||
// pairs := strings.Split(kv_store, ";")
|
||||
// for _, pair := range pairs {
|
||||
// values := strings.Split(pair, "=")
|
||||
// if len(values) != 2 {
|
||||
// continue
|
||||
// }
|
||||
// gomap[values[0]] = values[1]
|
||||
// }
|
||||
// return gomap
|
||||
//}
|
||||
|
||||
//func MappingFromMap(gomap map[string]string) Mapping {
|
||||
// kv_store := make([]byte, 0)
|
||||
// for k, v := range gomap {
|
||||
// key_bytes := []byte(k)
|
||||
// key_bytes = append(key_bytes, 0x3d)
|
||||
// value_bytes := []byte(v)
|
||||
// value_bytes = append(value_bytes, 0x3b)
|
||||
// kv_store = append(kv_store, key_bytes...)
|
||||
// kv_store = append(kv_store, value_bytes...)
|
||||
// }
|
||||
// kv_size := uint16(len(kv_store))
|
||||
// var size [2]byte
|
||||
// binary.BigEndian.PutUint16(size[:], kv_size)
|
||||
// mapping := Mapping{}
|
||||
// mapping = append(mapping, size[:]...)
|
||||
// mapping = append(mapping, kv_store...)
|
||||
// return mapping
|
||||
//}
|
||||
|
@ -1,37 +1 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestToMapping(t *testing.T) {
|
||||
gomap := map[string]string{
|
||||
"a": "1",
|
||||
}
|
||||
mapping := MappingFromMap(gomap)
|
||||
if !bytes.Equal(mapping, []byte{0x00, 0x04, 0x61, 0x3d, 0x31, 0x3b}) {
|
||||
t.Fatal("go map to mapping did not create correct mapping")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMappingToMap(t *testing.T) {
|
||||
mapping := Mapping{0x00, 0x08, 0x61, 0x3d, 0x31, 0x3b, 0x62, 0x3d, 0x32, 0x3b}
|
||||
gomap := mapping.ToMap()
|
||||
if gomap["a"] != "1" {
|
||||
t.Fatal("map does not contain encoded data")
|
||||
}
|
||||
if gomap["b"] != "2" {
|
||||
t.Fatal("map does not comtain encoded data")
|
||||
}
|
||||
}
|
||||
|
||||
func TestToAndFromMapping(t *testing.T) {
|
||||
gomap := make(map[string]string)
|
||||
gomap["foo"] = "bar"
|
||||
mapping := MappingFromMap(gomap)
|
||||
gomap2 := mapping.ToMap()
|
||||
if gomap["foo"] != gomap2["foo"] {
|
||||
t.Fatal("rebuilt map has different data")
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ func (router_address RouterAddress) Expiration() (d Date) {
|
||||
}
|
||||
|
||||
func (router_address RouterAddress) TransportStyle() string {
|
||||
return string(
|
||||
return string( //String
|
||||
router_address[10:router_address.stringLength()],
|
||||
)
|
||||
}
|
||||
|
1
lib/common/router_address_test.go
Normal file
1
lib/common/router_address_test.go
Normal file
@ -0,0 +1 @@
|
||||
package common
|
@ -1,41 +1,24 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/bounce-chat/go-i2p/lib/crypto"
|
||||
)
|
||||
|
||||
type RouterIdentity []byte
|
||||
|
||||
func (router_identity RouterIdentity) PublicKey() (key crypto.ElgPublicKey) {
|
||||
copy(router_identity[:256], key[:])
|
||||
return
|
||||
return KeysAndCert(router_identity).PublicKey()
|
||||
}
|
||||
|
||||
func (router_identity RouterIdentity) SigningPublicKey() (key crypto.SigningPublicKey) {
|
||||
cert := router_identity.Certificate()
|
||||
if cert.Type() == CERT_KEY {
|
||||
key = KeyCert(cert).SigningPublicKey()
|
||||
} else {
|
||||
var pk crypto.DSAPublicKey
|
||||
copy(pk[:], router_identity[256:256+128])
|
||||
key = pk
|
||||
}
|
||||
return
|
||||
return KeysAndCert(router_identity).SigningPublicKey()
|
||||
}
|
||||
|
||||
func (router_identity RouterIdentity) Certificate() (cert Certificate) {
|
||||
copy(router_identity[256+128:], cert)
|
||||
return
|
||||
return KeysAndCert(router_identity).Certificate()
|
||||
}
|
||||
|
||||
func readRouterIdentity(data []byte) (RouterIdentity, []byte, error) {
|
||||
var router_identity RouterIdentity
|
||||
copy(data[:387], router_identity)
|
||||
n := router_identity.Certificate().Len()
|
||||
if n == -1 {
|
||||
return router_identity, data, errors.New("invalid certificate")
|
||||
}
|
||||
router_identity = append(router_identity, data[387:n]...)
|
||||
return router_identity, data[387+n:], nil
|
||||
func ReadRouterIdentity(data []byte) (RouterIdentity, []byte, error) {
|
||||
keys_and_certs, remainder, err := ReadKeysAndCert(data)
|
||||
return RouterIdentity(keys_and_certs), remainder, err
|
||||
}
|
||||
|
@ -3,18 +3,18 @@ package common
|
||||
type RouterInfo []byte
|
||||
|
||||
func (router_info RouterInfo) RouterIdentity() RouterIdentity {
|
||||
router_identity, _, _ := readRouterIdentity(router_info)
|
||||
router_identity, _, _ := ReadRouterIdentity(router_info)
|
||||
return router_identity
|
||||
}
|
||||
|
||||
func (router_info RouterInfo) Published() (d Date) {
|
||||
_, remainder, _ := readRouterIdentity(router_info)
|
||||
_, remainder, _ := ReadRouterIdentity(router_info)
|
||||
copy(remainder[:8], d[:])
|
||||
return
|
||||
}
|
||||
|
||||
func (router_info RouterInfo) RouterAddressCount() int {
|
||||
_, remainder, _ := readRouterIdentity(router_info)
|
||||
_, remainder, _ := ReadRouterIdentity(router_info)
|
||||
return Integer([]byte{remainder[8]})
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ func (router_info RouterInfo) Signature() []byte {
|
||||
sig_size := router_info.
|
||||
RouterIdentity().
|
||||
Certificate().
|
||||
signatureSize()
|
||||
SignatureSize()
|
||||
return router_info[offset:sig_size]
|
||||
}
|
||||
|
||||
|
1
lib/common/router_info_test.go
Normal file
1
lib/common/router_info_test.go
Normal file
@ -0,0 +1 @@
|
||||
package common
|
3
lib/common/session_key.go
Normal file
3
lib/common/session_key.go
Normal file
@ -0,0 +1,3 @@
|
||||
package common
|
||||
|
||||
type SessionKey [32]byte
|
3
lib/common/session_tag.go
Normal file
3
lib/common/session_tag.go
Normal file
@ -0,0 +1,3 @@
|
||||
package common
|
||||
|
||||
type SessionTag [32]byte
|
@ -6,20 +6,66 @@ import (
|
||||
|
||||
type String []byte
|
||||
|
||||
func ReadString(data []byte) (str String, remainder []byte, err error) {
|
||||
if len(data) == 0 {
|
||||
err = errors.New("no string in empty byte slice")
|
||||
return
|
||||
func (str String) Length() (int, error) {
|
||||
if len(str) == 0 {
|
||||
// log
|
||||
return 0, errors.New("error parsing string: zero length")
|
||||
}
|
||||
length := Integer([]byte{data[0]})
|
||||
data = data[1:]
|
||||
|
||||
if len(data) < length {
|
||||
str = data
|
||||
err = errors.New("string longer than provided slice")
|
||||
return
|
||||
length := Integer([]byte{str[0]})
|
||||
inferred_len := length + 1
|
||||
str_len := len(str)
|
||||
if inferred_len > str_len {
|
||||
// log
|
||||
return length, errors.New("string parsing warning: string data is shorter than specified by length")
|
||||
} else if str_len > inferred_len {
|
||||
//log
|
||||
return length, errors.New("string parsing warning: string contains data beyond length")
|
||||
}
|
||||
str = data[:length]
|
||||
remainder = data[length:]
|
||||
return
|
||||
return length, nil
|
||||
}
|
||||
|
||||
func (str String) Data() ([]byte, error) {
|
||||
length, err := str.Length()
|
||||
if err != nil {
|
||||
switch err.Error() {
|
||||
case "error parsing string: zero length":
|
||||
return make([]byte, 0), err
|
||||
case "string parsing warning: string data is shorter than specified by length":
|
||||
return str[1:], err
|
||||
case "string parsing warning: string contains data beyond length":
|
||||
return str[1 : length+1], err
|
||||
}
|
||||
}
|
||||
return str[1:], nil
|
||||
}
|
||||
|
||||
func (str String) GoString() (string, error) {
|
||||
content, err := str.Data()
|
||||
return string(content), err
|
||||
}
|
||||
|
||||
func ToI2PString(data []byte) (String, error) {
|
||||
data_len := len(data)
|
||||
if data_len >= 256 {
|
||||
return make([]byte, 0), errors.New("cannot store that much data in I2P string")
|
||||
}
|
||||
i2p_string := []byte{byte(data_len)}
|
||||
i2p_string = append(i2p_string, data...)
|
||||
return String(i2p_string), nil
|
||||
}
|
||||
|
||||
func ReadString(data []byte) (String, []byte, error) {
|
||||
str := String(data)
|
||||
length, err := String(data).Length()
|
||||
if err != nil {
|
||||
switch err.Error() {
|
||||
case "error parsing string: zero length":
|
||||
return String{}, make([]byte, 0), err
|
||||
case "string parsing warning: string data is shorter than specified by length":
|
||||
return str, make([]byte, 0), err
|
||||
case "string parsing warning: string contains data beyond length":
|
||||
return String(str[:length+1]), str[length+1:], err
|
||||
}
|
||||
}
|
||||
return str, make([]byte, 0), nil
|
||||
}
|
||||
|
@ -2,47 +2,147 @@ package common
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestStringReportsCorrectLength(t *testing.T) {
|
||||
str_len, err := String([]byte{0x02, 0x00, 0x00}).Length()
|
||||
if str_len != 2 {
|
||||
t.Fatal("string.Length() did not report correct length")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal("string.Length() reported an error on valid string:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringReportsLengthZeroError(t *testing.T) {
|
||||
str_len, err := String(make([]byte, 0)).Length()
|
||||
if str_len != 0 {
|
||||
t.Fatal("string.Length() reported non-zero length on empty slice")
|
||||
}
|
||||
if err == nil || err.Error() != "error parsing string: zero length" {
|
||||
t.Fatal("string.Length() reported incorrect error on zero length slice:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringReportsExtraDataError(t *testing.T) {
|
||||
str_len, err := String([]byte{0x01, 0x00, 0x00}).Length()
|
||||
if str_len != 1 {
|
||||
t.Fatal("string.Length() reported wrong size when extra data present")
|
||||
}
|
||||
if err == nil || err.Error() != "string parsing warning: string contains data beyond length" {
|
||||
t.Fatal("string.Length() reported incorrect error on extra data:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringDataReportsLengthZeroError(t *testing.T) {
|
||||
str_len, err := String([]byte{0x01}).Length()
|
||||
if str_len != 1 {
|
||||
t.Fatal("string.Length() reported wring length with missing data", str_len)
|
||||
}
|
||||
if err == nil || err.Error() != "string parsing warning: string data is shorter than specified by length" {
|
||||
t.Fatal("string.Length() reported wrong error when data was missing", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringDataReportsExtraDataError(t *testing.T) {
|
||||
data, err := String([]byte{0x01, 0x00, 0x01}).Data()
|
||||
data_len := len(data)
|
||||
if data_len != 1 {
|
||||
t.Fatal("string.Data() returned wrong size data for length with extra data:", data_len)
|
||||
}
|
||||
if err == nil || err.Error() != "string parsing warning: string contains data beyond length" {
|
||||
t.Fatal("string.Length() reported wrong error with extra data", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringDataEmptyWhenZeroLength(t *testing.T) {
|
||||
data, err := String(make([]byte, 0)).Data()
|
||||
data_len := len(data)
|
||||
if data_len != 0 {
|
||||
t.Fatal("string.Data() returned data when none was present:", data_len)
|
||||
}
|
||||
if err == nil || err.Error() != "error parsing string: zero length" {
|
||||
t.Fatal("string.Length() reported wrong error with no data", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringDataErrorWhenNonZeroLengthOnly(t *testing.T) {
|
||||
data, err := String([]byte{0x01}).Data()
|
||||
data_len := len(data)
|
||||
if data_len != 0 {
|
||||
t.Fatal("string.Data() returned data when only length was present:", data_len)
|
||||
}
|
||||
if err == nil || err.Error() != "string parsing warning: string data is shorter than specified by length" {
|
||||
t.Fatal("string.Length() reported wrong error with length but no data", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestToI2PStringFormatsCorrectly(t *testing.T) {
|
||||
i2p_string, err := ToI2PString([]byte{0x22, 0x33})
|
||||
if err != nil {
|
||||
t.Fatal("ToI2PString() returned error on valid data:", err)
|
||||
}
|
||||
if i2p_string[0] != 0x02 {
|
||||
t.Fatal("ToI2PString() did not prepend the correct length")
|
||||
}
|
||||
if i2p_string[1] != 0x22 && i2p_string[2] != 0x33 {
|
||||
t.Fatal("ToI2PString() did not preserve string")
|
||||
}
|
||||
}
|
||||
|
||||
func TestToI2PStringReportsOverflows(t *testing.T) {
|
||||
i2p_string, err := ToI2PString(make([]byte, 256))
|
||||
if len(i2p_string) != 0 {
|
||||
t.Fatal("ToI2PString() returned data when overflowed")
|
||||
}
|
||||
if err == nil || err.Error() != "cannot store that much data in I2P string" {
|
||||
t.Fatal("ToI2pString() did not report overflow")
|
||||
}
|
||||
_, err = ToI2PString(make([]byte, 255))
|
||||
if err != nil {
|
||||
t.Fatal("ToI2PString() reported error with acceptable size:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadStringReadsLength(t *testing.T) {
|
||||
bytes := []byte{0x01, 0x04, 0x06}
|
||||
str, remainder, err := ReadString(bytes)
|
||||
if err != nil {
|
||||
t.Fatal("ReadString() returner error,", err)
|
||||
if err == nil || err.Error() != "string parsing warning: string contains data beyond length" {
|
||||
t.Fatal("ReadString(t *testing.T) returned incorrect error,", err)
|
||||
}
|
||||
if len(str) != 1 {
|
||||
t.Fatal("ReadString() did not return correct string length:", len(str))
|
||||
if len(str) != 2 {
|
||||
t.Fatal("ReadString(t *testing.T) did not return correct string length:", len(str))
|
||||
}
|
||||
if str[0] != 0x04 {
|
||||
t.Fatal("ReadString() did not return correct string")
|
||||
if str[0] != 0x01 && str[1] != 0x04 {
|
||||
t.Fatal("ReadString(t *testing.T) did not return correct string")
|
||||
}
|
||||
if len(remainder) != 1 {
|
||||
t.Fatal("ReadString() did not return correct remainder length")
|
||||
t.Fatal("ReadString(t *testing.T) did not return correct remainder length")
|
||||
}
|
||||
if remainder[0] != 0x06 {
|
||||
t.Fatal("ReadString() did not return correct remainder")
|
||||
t.Fatal("ReadString(t *testing.T) did not return correct remainder")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadStringErrWhenEmptySlice(t *testing.T) {
|
||||
bytes := make([]byte, 0)
|
||||
_, _, err := ReadString(bytes)
|
||||
if err != nil && err.Error() != "no string in empty byte slice" {
|
||||
t.Fatal("ReadString() did not report empty slice error", err)
|
||||
if err != nil && err.Error() != "error parsing string: zero length" {
|
||||
t.Fatal("ReadString(t *testing.T) did not report empty slice error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadStringErrWhenStringTooLong(t *testing.T) {
|
||||
func TestReadStringErrWhenDataTooShort(t *testing.T) {
|
||||
bytes := []byte{0x03, 0x01}
|
||||
str, remainder, err := ReadString(bytes)
|
||||
if err != nil && err.Error() != "string longer than provided slice" {
|
||||
t.Fatal("ReadString() did not report string too long", err)
|
||||
if err != nil && err.Error() != "string parsing warning: string data is shorter than specified by length" {
|
||||
t.Fatal("ReadString(t *testing.T) did not report string too long", err)
|
||||
}
|
||||
if len(str) != 1 {
|
||||
t.Fatal("ReadString() did not return the slice as string when too long")
|
||||
if len(str) != 2 {
|
||||
t.Fatal("ReadString(t *testing.T) did not return the slice as string when too long")
|
||||
}
|
||||
if str[0] != 0x01 {
|
||||
t.Fatal("ReadString() did not return the correct partial string")
|
||||
if str[0] != 0x03 && str[1] != 0x01 {
|
||||
t.Fatal("ReadString(t *testing.T) did not return the correct partial string")
|
||||
}
|
||||
if len(remainder) != 0 {
|
||||
t.Fatal("ReadString() returned a remainder when the string was too long")
|
||||
t.Fatal("ReadString(t *testing.T) returned a remainder when the string data was too short")
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user