3 Commits

16 changed files with 485 additions and 203 deletions

View File

@ -96,14 +96,39 @@ func (c *Certificate) ExcessBytes() []byte {
return nil
}
// Bytes returns the entire certificate in []byte form, trims payload to specified length.
// Data returns the payload of a Certificate, payload is trimmed to the specified length
func (c *Certificate) Data() []byte {
length := c.Length()
if length == 0 {
return []byte{}
}
if length > len(c.payload) {
log.WithFields(logrus.Fields{
"specified_length": length,
"actual_length": len(c.payload),
}).Warn("Certificate payload shorter than specified length")
return c.payload
}
return c.payload[:length]
}
// Bytes returns the entire certificate in []byte form
func (c *Certificate) Bytes() []byte {
if c.kind.Int() == CERT_NULL {
return []byte{0, 0, 0}
}
bytes := c.kind.Bytes()
bytes = append(bytes, c.len.Bytes()...)
bytes = append(bytes, c.Data()...)
log.WithFields(logrus.Fields{
"bytes_length": len(bytes),
"cert_type": c.kind.Int(),
}).Debug("Generated bytes for certificate")
return bytes
}
@ -130,21 +155,6 @@ func (c *Certificate) Length() (length int) {
return
}
// Data returns the payload of a Certificate, payload is trimmed to the specified length.
func (c *Certificate) Data() (data []byte) {
lastElement := c.Length()
if lastElement > len(c.payload) {
data = c.payload
log.Warn("Certificate payload shorter than specified length")
} else {
data = c.payload[0:lastElement]
}
log.WithFields(logrus.Fields{
"data_length": len(data),
}).Debug("Retrieved certificate data")
return
}
// readCertificate creates a new Certficiate from []byte
// returns err if the certificate is too short or if the payload doesn't match specified length.
func readCertificate(data []byte) (certificate Certificate, err error) {
@ -156,44 +166,67 @@ func readCertificate(data []byte) (certificate Certificate, err error) {
log.WithFields(logrus.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": len(data),
"reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()),
"reason": "too short (len < CERT_MIN_SIZE)",
}).Error("invalid certificate, empty")
err = fmt.Errorf("error parsing certificate: certificate is empty")
return
case 1, 2:
certificate.kind = Integer(data[0 : len(data)-1])
certificate.kind = Integer(data[0:1])
certificate.len = Integer([]byte{0})
log.WithFields(logrus.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": len(data),
"reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()),
"reason": "too short (len < CERT_MIN_SIZE)",
}).Error("invalid certificate, too short")
err = fmt.Errorf("error parsing certificate: certificate is too short")
return
default:
certificate.kind = Integer(data[0:1])
certificate.len = Integer(data[1:3])
payloadLength := len(data) - CERT_MIN_SIZE
certificate.payload = data[CERT_MIN_SIZE:]
if certificate.len.Int() > len(data)-CERT_MIN_SIZE {
err = fmt.Errorf("certificate parsing warning: certificate data is shorter than specified by length")
// Validate certificate type
if certificate.kind.Int() < CERT_NULL || certificate.kind.Int() > CERT_KEY {
log.WithFields(logrus.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": certificate.len.Int(),
"certificate_payload_length": payloadLength,
"data_bytes:": string(data),
"kind_bytes": data[0:1],
"len_bytes": data[1:3],
"reason": err.Error(),
}).Error("invalid certificate, shorter than specified by length")
"at": "(Certificate) NewCertificate",
"type": certificate.kind.Int(),
}).Error("invalid certificate type")
err = fmt.Errorf("error parsing certificate: invalid type: %d", certificate.kind.Int())
return
}
log.WithFields(logrus.Fields{
"type": certificate.kind.Int(),
"length": certificate.len.Int(),
}).Debug("Successfully created new certificate")
return
// Handle NULL certificates
if certificate.kind.Int() == CERT_NULL && certificate.len.Int() != 0 {
log.WithFields(logrus.Fields{
"at": "(Certificate) NewCertificate",
"length": certificate.len.Int(),
}).Error("NULL certificate must have zero length")
err = fmt.Errorf("error parsing certificate: NULL certificate must have zero length")
return
}
// Validate payload length
expectedLength := certificate.len.Int()
actualLength := len(data) - CERT_MIN_SIZE
if expectedLength > actualLength {
log.WithFields(logrus.Fields{
"at": "(Certificate) NewCertificate",
"expected_length": expectedLength,
"actual_length": actualLength,
}).Error("certificate data shorter than specified length")
err = fmt.Errorf("error parsing certificate: data shorter than specified length")
return
}
certificate.payload = data[CERT_MIN_SIZE:]
}
log.WithFields(logrus.Fields{
"type": certificate.kind.Int(),
"length": certificate.len.Int(),
}).Debug("Successfully parsed certificate")
return
}
// ReadCertificate creates a Certificate from []byte and returns any ExcessBytes at the end of the input.

View File

@ -38,7 +38,8 @@ func (i Date) Bytes() []byte {
// Int returns the Date as a Go integer.
func (i Date) Int() int {
return intFromBytes(i.Bytes())
val, _ := intFromBytes(i.Bytes())
return val
}
// Time takes the value stored in date as an 8 byte big-endian integer representing the

View File

@ -2,6 +2,8 @@ package data
import (
"crypto/sha256"
"crypto/subtle"
"errors"
"io"
)
@ -10,38 +12,68 @@ import (
Accurate for version 0.9.49
Description
Represents the SHA256 of some data.
Represents the SHA256 of some data. Used throughout I2P for data verification
and identity representation. Must be compared using constant-time operations
to prevent timing attacks.
Contents
32 bytes
[I2P Hash]:
32 bytes representing a SHA256 hash value
*/
// Hash is the represenation of an I2P Hash.
//
var (
ErrInvalidHashSize = errors.New("invalid hash size")
ErrNilReader = errors.New("nil reader")
)
// Hash is the representation of an I2P Hash.
// It is always exactly 32 bytes containing a SHA256 sum.
//
// https://geti2p.net/spec/common-structures#hash
type Hash [32]byte
// Bytes returns a copy of the Hash as a 32-byte array.
// This prevents modification of the original hash value.
func (h Hash) Bytes() [32]byte {
return h
}
// Equal compares two hashes in constant time.
// Returns true if the hashes are identical.
func (h Hash) Equal(other Hash) bool {
return subtle.ConstantTimeCompare(h[:], other[:]) == 1
}
// IsZero returns true if the hash is all zeros.
func (h Hash) IsZero() bool {
var zero Hash
return h.Equal(zero)
}
// HashData returns the SHA256 sum of a []byte input as Hash.
func HashData(data []byte) (h Hash) {
// log.Println("Hashing Data:", data)
h = sha256.Sum256(data)
return
// Never returns an error as SHA256 operates on any input length.
func HashData(data []byte) Hash {
if data == nil {
data = []byte{} // Handle nil input gracefully
}
return sha256.Sum256(data)
}
// HashReader returns the SHA256 sum from all data read from an io.Reader.
// return error if one occurs while reading from reader
func HashReader(r io.Reader) (h Hash, err error) {
sha := sha256.New()
_, err = io.Copy(sha, r)
if err == nil {
d := sha.Sum(nil)
copy(h[:], d)
// Returns an error if one occurs while reading from reader or if reader is nil.
func HashReader(r io.Reader) (Hash, error) {
var h Hash
if r == nil {
return h, ErrNilReader
}
return
}
sha := sha256.New()
_, err := io.Copy(sha, r)
if err != nil {
return h, err
}
sum := sha.Sum(nil)
copy(h[:], sum)
return h, nil
}

View File

@ -0,0 +1,65 @@
package data
import (
"io"
"strings"
"testing"
)
func TestHash(t *testing.T) {
tests := []struct {
name string
data []byte
want Hash
}{
{
name: "Empty input",
data: []byte{},
want: HashData([]byte{}),
},
{
name: "Nil input",
data: nil,
want: HashData([]byte{}),
},
// Add more test cases
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := HashData(tt.data)
if !got.Equal(tt.want) {
t.Errorf("HashData() = %v, want %v", got, tt.want)
}
})
}
}
func TestHashReader(t *testing.T) {
tests := []struct {
name string
reader io.Reader
wantErr bool
}{
{
name: "Nil reader",
reader: nil,
wantErr: true,
},
{
name: "Empty reader",
reader: strings.NewReader(""),
wantErr: false,
},
// Add more test cases
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := HashReader(tt.reader)
if (err != nil) != tt.wantErr {
t.Errorf("HashReader() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

View File

@ -2,13 +2,15 @@ package data
import (
"encoding/binary"
"errors"
"math"
)
// MAX_INTEGER_SIZE is the maximum length of an I2P integer in bytes.
const MAX_INTEGER_SIZE = 8
/*
[I2P Hash]
[I2P Integer]
Accurate for version 0.9.49
Description
@ -18,68 +20,112 @@ Contents
1 to 8 bytes in network byte order (big endian) representing an unsigned integer.
*/
// Integer is the represenation of an I2P Integer.
//
// https://geti2p.net/spec/common-structures#integer
var (
// ErrInvalidSize indicates the requested integer size is invalid (<=0 or >MAX_INTEGER_SIZE)
ErrInvalidSize = errors.New("invalid integer size")
// ErrInsufficientData indicates there isn't enough data to read the requested size
ErrInsufficientData = errors.New("insufficient data")
// ErrNegativeValue indicates an attempt to create an Integer from a negative value
ErrNegativeValue = errors.New("negative values not allowed")
// ErrIntegerOverflow indicates the value exceeds the maximum allowed size
ErrIntegerOverflow = errors.New("integer overflow")
)
// Integer is the representation of an I2P Integer.
// It contains 1 to 8 bytes in network byte order (big endian)
// representing an unsigned integer value.
type Integer []byte
// Bytes returns the raw []byte content of an Integer.
// This represents the big-endian encoded form of the integer.
func (i Integer) Bytes() []byte {
return i[:]
return i
}
// Int returns the Date as a Go integer
// Int returns the Integer as a Go integer.
// Returns an error if the value would overflow on the current platform
// or if the encoding is invalid.
func (i Integer) Int() int {
return intFromBytes(i.Bytes())
val, _ := intFromBytes(i)
return val
}
// ReadInteger returns an Integer from a []byte of specified length.
// The remaining bytes after the specified length are also returned.
func ReadInteger(bytes []byte, size int) (Integer, []byte) {
if len(bytes) < size {
return bytes[:size], bytes[len(bytes):]
// Returns an error if size is invalid or there isn't enough data.
func ReadInteger(bytes []byte, size int) (Integer, []byte, error) {
if size <= 0 {
return nil, bytes, ErrInvalidSize
}
return bytes[:size], bytes[size:]
if size > len(bytes) {
return nil, bytes, ErrInsufficientData
}
return Integer(bytes[:size]), bytes[size:], nil
}
// NewInteger creates a new Integer from []byte using ReadInteger.
// Limits the length of the created Integer to MAX_INTEGER_SIZE.
// Returns a pointer to Integer unlike ReadInteger.
func NewInteger(bytes []byte, size int) (integer *Integer, remainder []byte, err error) {
integerSize := MAX_INTEGER_SIZE
if size < MAX_INTEGER_SIZE {
integerSize = size
// Returns a pointer to Integer and the remaining bytes.
// Returns an error if size is invalid or there isn't enough data.
func NewInteger(bytes []byte, size int) (*Integer, []byte, error) {
if size <= 0 || size > MAX_INTEGER_SIZE {
return nil, bytes, ErrInvalidSize
}
intBytes := bytes[:integerSize]
remainder = bytes[integerSize:]
i, _ := ReadInteger(intBytes, integerSize)
integer = &i
return
if len(bytes) < size {
return nil, bytes, ErrInsufficientData
}
integer, remainder, err := ReadInteger(bytes, size)
if err != nil {
return nil, bytes, err
}
return &integer, remainder, nil
}
// NewIntegerFromInt creates a new Integer from a Go integer of a specified []byte length.
func NewIntegerFromInt(value int, size int) (integer *Integer, err error) {
bytes := make([]byte, MAX_INTEGER_SIZE)
binary.BigEndian.PutUint64(bytes, uint64(value))
integerSize := MAX_INTEGER_SIZE
if size < MAX_INTEGER_SIZE {
integerSize = size
// The value must be non-negative and fit within the specified number of bytes.
// Returns an error if the size is invalid or the value cannot be represented.
func NewIntegerFromInt(value int, size int) (*Integer, error) {
if size <= 0 || size > MAX_INTEGER_SIZE {
return nil, ErrInvalidSize
}
objinteger, _, err := NewInteger(bytes[MAX_INTEGER_SIZE-integerSize:], integerSize)
integer = objinteger
return
if value < 0 {
return nil, ErrNegativeValue
}
// Check if value fits in specified size
maxVal := int(math.Pow(2, float64(size*8))) - 1
if value > maxVal {
return nil, ErrIntegerOverflow
}
buf := make([]byte, MAX_INTEGER_SIZE)
binary.BigEndian.PutUint64(buf, uint64(value))
data := buf[MAX_INTEGER_SIZE-size:]
integer := Integer(data)
return &integer, nil
}
// Interpret a slice of bytes from length 0 to length 8 as a big-endian
// integer and return an int representation.
func intFromBytes(number []byte) (value int) {
num_len := len(number)
if num_len < MAX_INTEGER_SIZE {
number = append(
make([]byte, MAX_INTEGER_SIZE-num_len),
number...,
)
// intFromBytes interprets a slice of bytes from length 0 to length 8 as a big-endian
// integer and returns an int representation.
// Returns an error if the value would overflow on the current platform
// or if the input is invalid.
func intFromBytes(number []byte) (int, error) {
if len(number) == 0 {
return 0, nil
}
value = int(binary.BigEndian.Uint64(number))
return
}
if len(number) > MAX_INTEGER_SIZE {
return 0, ErrInvalidSize
}
padded := make([]byte, MAX_INTEGER_SIZE)
copy(padded[MAX_INTEGER_SIZE-len(number):], number)
val := int64(binary.BigEndian.Uint64(padded))
if val > math.MaxInt32 || val < math.MinInt32 {
return 0, ErrIntegerOverflow
}
return int(val), nil
}

View File

@ -30,3 +30,32 @@ func TestIsZeroWithNoData(t *testing.T) {
assert.Equal(integer.Int(), 0, "Integer() did not correctly parse zero length byte slice")
}
func TestIntegerEdgeCases(t *testing.T) {
tests := []struct {
name string
input []byte
size int
wantErr bool
wantInt int
}{
{"empty input", []byte{}, 1, true, 0},
{"zero size", []byte{1}, 0, true, 0},
{"oversized", []byte{1}, 9, true, 0},
{"valid small", []byte{42}, 1, false, 42},
{"valid max", []byte{1, 2, 3, 4, 5, 6, 7, 8}, 8, false, 72623859790382856},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
i, _, err := NewInteger(tt.input, tt.size)
if (err != nil) != tt.wantErr {
t.Errorf("NewInteger() error = %v, wantErr %v", err, tt.wantErr)
return
}
if err == nil && i.Int() != tt.wantInt {
t.Errorf("Integer.Int() = %v, want %v", i.Int(), tt.wantInt)
}
})
}
}

View File

@ -2,6 +2,7 @@ package data
import (
"errors"
"fmt"
"github.com/sirupsen/logrus"
)
@ -97,34 +98,20 @@ func (mapping *Mapping) HasDuplicateKeys() bool {
}
// GoMapToMapping converts a Go map of unformatted strings to *Mapping.
func GoMapToMapping(gomap map[string]string) (mapping *Mapping, err error) {
log.WithFields(logrus.Fields{
"input_map_size": len(gomap),
}).Debug("Converting Go map to Mapping")
func GoMapToMapping(gomap map[string]string) (*Mapping, error) {
map_vals := MappingValues{}
for k, v := range gomap {
key_str, kerr := ToI2PString(k)
if kerr != nil {
log.WithError(kerr).Error("Failed to convert key to I2PString")
err = kerr
return
key_str, err := ToI2PString(k)
if err != nil {
return nil, fmt.Errorf("key conversion error: %w", err)
}
val_str, verr := ToI2PString(v)
if verr != nil {
log.WithError(verr).Error("Failed to convert value to I2PString")
err = verr
return
val_str, err := ToI2PString(v)
if err != nil {
return nil, fmt.Errorf("value conversion error: %w", err)
}
map_vals = append(
map_vals,
[2]I2PString{key_str, val_str},
)
map_vals = append(map_vals, [2]I2PString{key_str, val_str})
}
mapping = ValuesToMapping(map_vals)
log.WithFields(logrus.Fields{
"mapping_size": len(map_vals),
}).Debug("Successfully converted Go map to Mapping")
return
return ValuesToMapping(map_vals), nil
}
// Check if the string parsing error indicates that the Mapping
@ -152,10 +139,37 @@ func beginsWith(bytes []byte, chr byte) bool {
return result
}
func (mapping *Mapping) addValue(key, value I2PString) error {
for _, pair := range *mapping.vals {
existingKey, _ := pair[0].Data()
newKey, _ := key.Data()
if existingKey == newKey {
return fmt.Errorf("duplicate key: %s", newKey)
}
}
*mapping.vals = append(*mapping.vals, [2]I2PString{key, value})
return nil
}
// ReadMapping returns Mapping from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
const MaxMappingSize = 65535 // Match Java I2P's maximum mapping size
func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error) {
if len(bytes) < 3 {
err = append(err, errors.New("mapping data too short"))
return
}
size, remainder, e := NewInteger(bytes, 2)
if e != nil {
log.WithError(e).Error("Failed to read Mapping size")
err = append(err, e)
}
if size.Int() > MaxMappingSize {
err = append(err, fmt.Errorf("mapping size %d exceeds maximum %d", size.Int(), MaxMappingSize))
return
}
log.WithFields(logrus.Fields{
"input_length": len(bytes),
}).Debug("Reading Mapping from bytes")
@ -168,16 +182,16 @@ func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error)
err = append(err, e)
return
}
size, remainder, e := NewInteger(bytes, 2)
if e != nil {
log.WithError(e).Error("Failed to read Mapping size")
err = append(err, e)
}
if size.Int() == 0 {
log.Warn("Mapping size is zero")
return
}
mapping.size = size
if mapping.size.Int() > len(remainder) {
err = append(err, fmt.Errorf("mapping size %d exceeds available data length %d",
mapping.size.Int(), len(remainder)))
return
}
map_bytes := remainder[:mapping.size.Int()]
remainder = remainder[mapping.size.Int():]
if len(remainder) == 0 {

View File

@ -1,6 +1,7 @@
package data
import (
"bytes"
"errors"
"sort"
@ -11,20 +12,37 @@ import (
type MappingValues [][2]I2PString
func (m MappingValues) Get(key I2PString) I2PString {
keyBytes, _ := key.Data()
if key == nil {
return nil
}
keyBytes, err := key.Data()
if err != nil {
return nil
}
log.WithFields(logrus.Fields{
"key": string(keyBytes),
}).Debug("Searching for key in MappingValues")
for _, pair := range m {
kb, _ := pair[0][0:].Data()
if pair[0] == nil {
continue
}
kb, err := pair[0].Data()
if err != nil {
continue
}
if kb == keyBytes {
data, _ := pair[1].Data()
log.WithFields(logrus.Fields{
"key": string(keyBytes),
"value": string(pair[1][1:]),
"value": string(data),
}).Debug("Found matching key in MappingValues")
return pair[1]
}
}
log.WithFields(logrus.Fields{
"key": string(keyBytes),
}).Debug("Key not found in MappingValues")
@ -64,10 +82,15 @@ func ValuesToMapping(values MappingValues) *Mapping {
// In practice routers do not seem to allow duplicate keys.
func mappingOrder(values MappingValues) {
sort.SliceStable(values, func(i, j int) bool {
// Lexographic sort on keys only
data1, _ := values[i][0].Data()
data2, _ := values[j][0].Data()
return data1 < data2
data1, err1 := values[i][0].Data()
data2, err2 := values[j][0].Data()
// Handle error cases by treating them as "less than"
if err1 != nil || err2 != nil {
return err1 == nil
}
return bytes.Compare([]byte(data1), []byte(data2)) < 0
})
}
@ -217,6 +240,6 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
"remainder_length": len(remainder_bytes),
"error_count": len(errs),
}).Debug("Finished reading MappingValues")
remainder_bytes = remainder
return
}

View File

@ -2,6 +2,7 @@ package data
import (
"fmt"
"reflect"
"testing"
)
@ -45,3 +46,41 @@ func TestMappingOrderSortsValuesThenKeys(t *testing.T) {
}
}
}
func TestMappingValuesEdgeCases(t *testing.T) {
k1, _ := ToI2PString("test")
tests := []struct {
name string
mv MappingValues
key I2PString
want I2PString
}{
{
name: "nil key",
mv: MappingValues{},
key: nil,
want: nil,
},
{
name: "empty mapping",
mv: MappingValues{},
key: k1,
want: nil,
},
{
name: "nil value in pair",
mv: MappingValues{{k1, nil}},
key: k1,
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := tt.mv.Get(tt.key)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("MappingValues.Get() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -5,7 +5,7 @@ import common "github.com/go-i2p/go-i2p/lib/common/router_identity"
func Fuzz(data []byte) int {
router_identity, _, _ := common.ReadRouterIdentity(data)
router_identity.Certificate()
//router_identity.publicKey()
//router_identity.signingPublicKey()
// router_identity.publicKey()
// router_identity.signingPublicKey()
return 0
}

View File

@ -29,6 +29,7 @@ payload :: data
import (
"errors"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
@ -110,46 +111,46 @@ func (key_certificate KeyCertificate) Data() ([]byte, error) {
}
// SigningPublicKeyType returns the signingPublicKey type as a Go integer.
func (key_certificate KeyCertificate) SigningPublicKeyType() (signing_pubkey_type int) {
signing_pubkey_type = key_certificate.spkType.Int()
log.WithFields(logrus.Fields{
"signing_pubkey_type": signing_pubkey_type,
}).Debug("Retrieved signingPublicKey type")
return key_certificate.spkType.Int()
func (key_certificate KeyCertificate) SigningPublicKeyType() int {
spk_type := key_certificate.spkType.Int()
log.WithFields(logrus.Fields{
"signing_pubkey_type": spk_type,
}).Debug("Retrieved signingPublicKey type")
return spk_type
}
// PublicKeyType returns the publicKey type as a Go integer.
func (key_certificate KeyCertificate) PublicKeyType() (pubkey_type int) {
pubkey_type = key_certificate.cpkType.Int()
log.WithFields(logrus.Fields{
"pubkey_type": pubkey_type,
}).Debug("Retrieved publicKey type")
return key_certificate.cpkType.Int()
func (key_certificate KeyCertificate) CryptoSize() int {
switch key_certificate.PublicKeyType() {
case KEYCERT_CRYPTO_ELG:
return KEYCERT_CRYPTO_ELG_SIZE
case KEYCERT_CRYPTO_P256:
return KEYCERT_CRYPTO_P256_SIZE
case KEYCERT_CRYPTO_P384:
return KEYCERT_CRYPTO_P384_SIZE
case KEYCERT_CRYPTO_P521:
return KEYCERT_CRYPTO_P521_SIZE
case KEYCERT_CRYPTO_X25519:
return KEYCERT_CRYPTO_X25519_SIZE
default:
return 0
}
}
// ConstructPublicKey returns a publicKey constructed using any excess data that may be stored in the KeyCertififcate.
// Returns enr errors encountered while parsing.
func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_key crypto.PublicKey, err error) {
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Constructing publicKey from keyCertificate")
key_type := key_certificate.PublicKeyType()
if err != nil {
return
}
data_len := len(data)
if data_len < key_certificate.CryptoSize() {
log.WithFields(logrus.Fields{
"at": "(keyCertificate) ConstructPublicKey",
"data_len": data_len,
"required_len": KEYCERT_PUBKEY_SIZE,
"reason": "not enough data",
}).Error("error constructing public key")
err = errors.New("error constructing public key: not enough data")
return
}
switch key_type {
case KEYCERT_CRYPTO_ELG:
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Constructing publicKey from keyCertificate")
key_type := key_certificate.PublicKeyType()
data_len := len(data)
if data_len < key_certificate.CryptoSize() {
return nil, errors.New("error constructing public key: not enough data")
}
// Implementation missing here - needs to construct appropriate key type
switch key_type {
case KEYCERT_CRYPTO_ELG:
var elg_key crypto.ElgPublicKey
copy(elg_key[:], data[KEYCERT_PUBKEY_SIZE-KEYCERT_CRYPTO_ELG_SIZE:KEYCERT_PUBKEY_SIZE])
public_key = elg_key
@ -159,13 +160,25 @@ func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_ke
copy(ed25519_key[:], data[KEYCERT_PUBKEY_SIZE-KEYCERT_CRYPTO_ELG_SIZE:KEYCERT_PUBKEY_SIZE])
public_key = ed25519_key
log.Debug("Constructed Ed25519PublicKey")
default:
log.WithFields(logrus.Fields{
"key_type": key_type,
}).Warn("Unknown public key type")
}
case KEYCERT_CRYPTO_P256:
//return crypto.CreatePublicKey(data[:KEYCERT_CRYPTO_P256_SIZE])
case KEYCERT_CRYPTO_P384:
//return crypto.CreatePublicKey(data[:KEYCERT_CRYPTO_P384_SIZE])
case KEYCERT_CRYPTO_P521:
//return crypto.CreatePublicKey(data[:KEYCERT_CRYPTO_P521_SIZE])
default:
return nil, errors.New("error constructing public key: unknown key type")
}
return nil, errors.New("error constructing public key: unknown key type")
}
return
// PublicKeyType returns the publicKey type as a Go integer.
func (key_certificate KeyCertificate) PublicKeyType() int {
pk_type := key_certificate.cpkType.Int()
log.WithFields(logrus.Fields{
"pubkey_type": pk_type,
}).Debug("Retrieved publicKey type")
return pk_type
}
// ConstructSigningPublicKey returns a SingingPublicKey constructed using any excess data that may be stored in the KeyCertificate.
@ -268,24 +281,6 @@ func (key_certificate KeyCertificate) SignatureSize() (size int) {
return sizes[int(key_type)]
}
// CryptoSize return the size of a Public Key corresponding to the Key Certificate's publicKey type.
func (key_certificate KeyCertificate) CryptoSize() (size int) {
sizes := map[int]int{
KEYCERT_CRYPTO_ELG: KEYCERT_CRYPTO_ELG_SIZE,
KEYCERT_CRYPTO_P256: KEYCERT_CRYPTO_P256_SIZE,
KEYCERT_CRYPTO_P384: KEYCERT_CRYPTO_P384_SIZE,
KEYCERT_CRYPTO_P521: KEYCERT_CRYPTO_P521_SIZE,
KEYCERT_CRYPTO_X25519: KEYCERT_CRYPTO_X25519_SIZE,
}
key_type := key_certificate.PublicKeyType()
size = sizes[int(key_type)]
log.WithFields(logrus.Fields{
"key_type": key_type,
"crypto_size": size,
}).Debug("Retrieved crypto size")
return sizes[int(key_type)]
}
// NewKeyCertificate creates a new *KeyCertificate from []byte using ReadCertificate.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
@ -300,6 +295,10 @@ func NewKeyCertificate(bytes []byte) (key_certificate *KeyCertificate, remainder
log.WithError(err).Error("Failed to read Certificate")
return
}
if certificate.Type() != 5 { // Key certificate type must be 5
return nil, nil, errors.New("error parsing key certificate: invalid certificate type")
}
if len(bytes) < KEYCERT_MIN_SIZE {
log.WithError(err).Error("keyCertificate data too short")
err = errors.New("error parsing key certificate: not enough data")

View File

@ -174,7 +174,7 @@ func (router_info *RouterInfo) RouterIdentity() *RouterIdentity {
// IndentHash returns the identity hash (sha256 sum) for this RouterInfo.
func (router_info *RouterInfo) IdentHash() Hash {
log.Debug("Calculating IdentHash for RouterInfo")
//data, _ := router_info.RouterIdentity().keyCertificate.Data()
// data, _ := router_info.RouterIdentity().keyCertificate.Data()
cert := router_info.RouterIdentity().KeysAndCert.Certificate()
data := cert.Data()
hash := HashData(data)

View File

@ -3,6 +3,7 @@ package signature
import (
"fmt"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
)

View File

@ -185,7 +185,7 @@ func (v *Ed25519Verifier) Verify(data, sig []byte) (err error) {
type Ed25519PrivateKey ed25519.PrivateKey
func (k Ed25519PrivateKey) NewDecrypter() (Decrypter, error) {
//TODO implement me
// TODO implement me
panic("implement me")
}

View File

@ -30,7 +30,7 @@ type SigningPublicKey interface {
}
type PublicKey interface {
Len() int
Bytes() []byte
Bytes() []byte
NewEncrypter() (Encrypter, error)
}

View File

@ -21,11 +21,11 @@ type NoiseSession struct {
*sync.Cond
*NoiseTransport // The parent transport, which "Dialed" the connection to the peer whith whom we established the session
*HandshakeState
RecvQueue *cb.Queue
SendQueue *cb.Queue
VerifyCallback VerifyCallbackFunc
activeCall int32
Conn net.Conn
RecvQueue *cb.Queue
SendQueue *cb.Queue
VerifyCallback VerifyCallbackFunc
activeCall int32
Conn net.Conn
}
// RemoteAddr implements net.Conn