start working on basic key storage for own RI private keys
This commit is contained in:
@@ -132,7 +132,7 @@ func (keyCertificate KeyCertificate) PublicKeyType() (pubkey_type int) {
|
||||
|
||||
// ConstructPublicKey returns a publicKey constructed using any excess data that may be stored in the KeyCertififcate.
|
||||
// Returns enr errors encountered while parsing.
|
||||
func (keyCertificate KeyCertificate) ConstructPublicKey(data []byte) (public_key crypto.PublicKey, err error) {
|
||||
func (keyCertificate KeyCertificate) ConstructPublicKey(data []byte) (public_key crypto.RecievingPublicKey, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(data),
|
||||
}).Debug("Constructing publicKey from keyCertificate")
|
||||
|
@@ -80,7 +80,7 @@ total length: 387+ bytes
|
||||
// https://geti2p.net/spec/common-structures#keysandcert
|
||||
type KeysAndCert struct {
|
||||
KeyCertificate *KeyCertificate
|
||||
publicKey crypto.PublicKey
|
||||
publicKey crypto.RecievingPublicKey
|
||||
Padding []byte
|
||||
signingPublicKey crypto.SigningPublicKey
|
||||
}
|
||||
@@ -104,7 +104,7 @@ func (keys_and_cert KeysAndCert) Bytes() []byte {
|
||||
}
|
||||
|
||||
// publicKey returns the public key as a crypto.publicKey.
|
||||
func (keys_and_cert *KeysAndCert) PublicKey() (key crypto.PublicKey) {
|
||||
func (keys_and_cert *KeysAndCert) PublicKey() (key crypto.RecievingPublicKey) {
|
||||
return keys_and_cert.publicKey
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ func ReadKeysAndCertElgAndEd25519(data []byte) (keysAndCert *KeysAndCert, remain
|
||||
return
|
||||
}
|
||||
|
||||
func constructPublicKey(data []byte, cryptoType uint16) (crypto.PublicKey, error) {
|
||||
func constructPublicKey(data []byte, cryptoType uint16) (crypto.RecievingPublicKey, error) {
|
||||
switch cryptoType {
|
||||
case CRYPTO_KEY_TYPE_ELGAMAL:
|
||||
if len(data) != 256 {
|
||||
@@ -280,7 +280,7 @@ func constructSigningPublicKey(data []byte, sigType uint16) (crypto.SigningPubli
|
||||
// It validates the sizes of the provided keys and padding before assembling the struct.
|
||||
func NewKeysAndCert(
|
||||
keyCertificate *KeyCertificate,
|
||||
publicKey crypto.PublicKey,
|
||||
publicKey crypto.RecievingPublicKey,
|
||||
padding []byte,
|
||||
signingPublicKey crypto.SigningPublicKey,
|
||||
) (*KeysAndCert, error) {
|
||||
|
@@ -492,7 +492,7 @@ func (lease_set LeaseSet) OldestExpiration() (earliest Date, err error) {
|
||||
|
||||
func NewLeaseSet(
|
||||
destination Destination,
|
||||
encryptionKey crypto.PublicKey,
|
||||
encryptionKey crypto.RecievingPublicKey,
|
||||
signingKey crypto.SigningPublicKey,
|
||||
leases []Lease,
|
||||
signingPrivateKey crypto.SigningPrivateKey,
|
||||
|
@@ -4,13 +4,14 @@ import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/destination"
|
||||
"github.com/go-i2p/go-i2p/lib/common/key_certificate"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_address"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
"github.com/go-i2p/go-i2p/lib/common/signature"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/data"
|
||||
"github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
|
||||
@@ -23,7 +24,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func generateTestRouterInfo(t *testing.T) (*router_info.RouterInfo, crypto.PublicKey, crypto.SigningPublicKey, crypto.SigningPrivateKey, crypto.SigningPrivateKey, error) {
|
||||
func generateTestRouterInfo(t *testing.T) (*router_info.RouterInfo, crypto.RecievingPublicKey, crypto.SigningPublicKey, crypto.SigningPrivateKey, crypto.SigningPrivateKey, error) {
|
||||
// Generate signing key pair (Ed25519)
|
||||
var ed25519_privkey crypto.Ed25519PrivateKey
|
||||
_, err := (&ed25519_privkey).Generate()
|
||||
@@ -63,7 +64,7 @@ func generateTestRouterInfo(t *testing.T) (*router_info.RouterInfo, crypto.Publi
|
||||
copy(elg_pubkey[256-len(yBytes):], yBytes)
|
||||
|
||||
// Ensure that elg_pubkey implements crypto.PublicKey interface
|
||||
var _ crypto.PublicKey = elg_pubkey
|
||||
var _ crypto.RecievingPublicKey = elg_pubkey
|
||||
|
||||
// Create KeyCertificate specifying key types
|
||||
var payload bytes.Buffer
|
||||
@@ -176,7 +177,7 @@ func createTestLease(t *testing.T, index int, routerInfo *router_info.RouterInfo
|
||||
|
||||
return testLease, nil
|
||||
}
|
||||
func generateTestDestination(t *testing.T) (*destination.Destination, crypto.PublicKey, crypto.SigningPublicKey, crypto.SigningPrivateKey, error) {
|
||||
func generateTestDestination(t *testing.T) (*destination.Destination, crypto.RecievingPublicKey, crypto.SigningPublicKey, crypto.SigningPrivateKey, error) {
|
||||
// Generate client signing key pair (Ed25519)
|
||||
var ed25519_privkey crypto.Ed25519PrivateKey
|
||||
_, err := (&ed25519_privkey).Generate()
|
||||
|
@@ -52,7 +52,7 @@ func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder
|
||||
return
|
||||
}
|
||||
|
||||
func NewRouterIdentity(publicKey crypto.PublicKey, signingPublicKey crypto.SigningPublicKey, cert certificate.Certificate, padding []byte) (*RouterIdentity, error) {
|
||||
func NewRouterIdentity(publicKey crypto.RecievingPublicKey, signingPublicKey crypto.SigningPublicKey, cert certificate.Certificate, padding []byte) (*RouterIdentity, error) {
|
||||
log.Debug("Creating new RouterIdentity")
|
||||
|
||||
// Step 1: Create keyCertificate from the provided certificate.
|
||||
|
9
lib/common/router_info/new.go
Normal file
9
lib/common/router_info/new.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package router_info
|
||||
|
||||
import "github.com/go-i2p/go-i2p/lib/common/key_certificate"
|
||||
|
||||
func OwnedRouterInfo(keyCertificate key_certificate.KeyCertificate) *RouterInfo {
|
||||
return &RouterInfo{
|
||||
// ...
|
||||
}
|
||||
}
|
@@ -59,7 +59,7 @@ func TestCreateRouterInfo(t *testing.T) {
|
||||
copy(elg_pubkey[256-len(yBytes):], yBytes)
|
||||
|
||||
// Ensure that elg_pubkey implements crypto.PublicKey interface
|
||||
var _ crypto.PublicKey = elg_pubkey
|
||||
var _ crypto.RecievingPublicKey = elg_pubkey
|
||||
|
||||
// Create KeyCertificate specifying key types
|
||||
var payload bytes.Buffer
|
||||
|
@@ -3,10 +3,11 @@ package router_info
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/certificate"
|
||||
"github.com/go-i2p/go-i2p/lib/common/data"
|
||||
"github.com/go-i2p/go-i2p/lib/common/key_certificate"
|
||||
@@ -59,7 +60,7 @@ func generateTestRouterInfo(t *testing.T, publishedTime time.Time) (*RouterInfo,
|
||||
copy(elg_pubkey[256-len(yBytes):], yBytes)
|
||||
|
||||
// Ensure that elg_pubkey implements crypto.PublicKey interface
|
||||
var _ crypto.PublicKey = elg_pubkey
|
||||
var _ crypto.RecievingPublicKey = elg_pubkey
|
||||
|
||||
// Create KeyCertificate specifying key types
|
||||
var payload bytes.Buffer
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
@@ -185,9 +186,79 @@ func (v *Ed25519Verifier) Verify(data, sig []byte) (err error) {
|
||||
|
||||
type Ed25519PrivateKey ed25519.PrivateKey
|
||||
|
||||
func (k Ed25519PrivateKey) Bytes() []byte {
|
||||
return k
|
||||
}
|
||||
|
||||
func (k Ed25519PrivateKey) Zero() {
|
||||
for i := range k {
|
||||
k[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (k Ed25519PrivateKey) NewDecrypter() (Decrypter, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
if len(k) != ed25519.PrivateKeySize {
|
||||
return nil, errors.New("invalid ed25519 private key size")
|
||||
}
|
||||
d := &Ed25519Decrypter{
|
||||
privateKey: k,
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
type Ed25519Decrypter struct {
|
||||
privateKey Ed25519PrivateKey
|
||||
}
|
||||
|
||||
func (d *Ed25519Decrypter) Decrypt(data []byte) ([]byte, error) {
|
||||
return d.DecryptPadding(data, true)
|
||||
}
|
||||
|
||||
func (d *Ed25519Decrypter) DecryptPadding(data []byte, zeroPadding bool) ([]byte, error) {
|
||||
if len(data) != 514 && len(data) != 512 {
|
||||
return nil, errors.New("invalid ciphertext length")
|
||||
}
|
||||
|
||||
// Extract components based on padding
|
||||
var aBytes, bBytes []byte
|
||||
if zeroPadding {
|
||||
aBytes = data[1:258]
|
||||
bBytes = data[258:]
|
||||
} else {
|
||||
aBytes = data[0:256]
|
||||
bBytes = data[256:]
|
||||
}
|
||||
|
||||
// Convert to big integers
|
||||
a := new(big.Int).SetBytes(aBytes)
|
||||
b := new(big.Int).SetBytes(bBytes)
|
||||
|
||||
// Compute p = 2^255 - 19
|
||||
p := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 255), big.NewInt(19))
|
||||
|
||||
// Use private key to decrypt
|
||||
m := new(big.Int).ModInverse(a, p)
|
||||
if m == nil {
|
||||
return nil, errors.New("decryption failed: modular inverse does not exist")
|
||||
}
|
||||
|
||||
decrypted := new(big.Int).Mod(new(big.Int).Mul(b, m), p).Bytes()
|
||||
|
||||
// Remove padding and validate hash
|
||||
if len(decrypted) < 33 {
|
||||
return nil, errors.New("decryption failed: result too short")
|
||||
}
|
||||
|
||||
hashBytes := decrypted[1:33]
|
||||
message := decrypted[33:]
|
||||
|
||||
// Verify hash
|
||||
actualHash := sha256.Sum256(message)
|
||||
if !bytes.Equal(hashBytes, actualHash[:]) {
|
||||
return nil, errors.New("decryption failed: hash verification failed")
|
||||
}
|
||||
|
||||
return message, nil
|
||||
}
|
||||
|
||||
func (k Ed25519PrivateKey) NewSigner() (Signer, error) {
|
||||
|
11
lib/crypto/privatekey.go
Normal file
11
lib/crypto/privatekey.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package crypto
|
||||
|
||||
// PrivateKey is an interface for private keys
|
||||
type PrivateKey interface {
|
||||
// Public returns the public key corresponding to this private key
|
||||
Public() (SigningPublicKey, error)
|
||||
// Bytes returns the raw bytes of this private key
|
||||
Bytes() []byte
|
||||
// Zero clears all sensitive data from the private key
|
||||
Zero()
|
||||
}
|
6
lib/crypto/public.go
Normal file
6
lib/crypto/public.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package crypto
|
||||
|
||||
type PublicKey interface {
|
||||
Len() int
|
||||
Bytes() []byte
|
||||
}
|
@@ -28,7 +28,7 @@ type SigningPublicKey interface {
|
||||
Len() int
|
||||
Bytes() []byte
|
||||
}
|
||||
type PublicKey interface {
|
||||
type RecievingPublicKey interface {
|
||||
Len() int
|
||||
Bytes() []byte
|
||||
NewEncrypter() (Encrypter, error)
|
||||
|
109
lib/keys/routerinfo_keystore.go
Normal file
109
lib/keys/routerinfo_keystore.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
)
|
||||
|
||||
// RouterInfoKeystore is an implementation of KeyStore for storing and retrieving RouterInfo private keys and exporting RouterInfos
|
||||
type RouterInfoKeystore struct {
|
||||
dir string
|
||||
name string
|
||||
privateKey crypto.PrivateKey
|
||||
}
|
||||
|
||||
var riks KeyStore = &RouterInfoKeystore{}
|
||||
|
||||
// NewRouterInfoKeystore creates a new RouterInfoKeystore with fresh and new private keys
|
||||
// it accepts a directory to store the keys in and a name for the keys
|
||||
// then it generates new private keys for the routerInfo if none exist
|
||||
func NewRouterInfoKeystore(dir, name string) (*RouterInfoKeystore, error) {
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
err := os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var privateKey crypto.PrivateKey
|
||||
fullPath := filepath.Join(dir, name)
|
||||
if _, err := os.Stat(fullPath); os.IsNotExist(err) {
|
||||
privateKey, err = generateNewKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
keyData, err := os.ReadFile(fullPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
privateKey, err = loadExistingKey(keyData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &RouterInfoKeystore{
|
||||
dir: dir,
|
||||
name: name,
|
||||
privateKey: privateKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func generateNewKey() (crypto.Ed25519PrivateKey, error) {
|
||||
// Generate a new key pair
|
||||
_, priv, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Convert to our type
|
||||
return crypto.Ed25519PrivateKey(priv), nil
|
||||
}
|
||||
|
||||
func loadExistingKey(keyData []byte) (crypto.Ed25519PrivateKey, error) {
|
||||
// Validate key length
|
||||
if len(keyData) != ed25519.PrivateKeySize {
|
||||
return nil, errors.New("invalid key length")
|
||||
}
|
||||
|
||||
// Convert to our type
|
||||
return crypto.Ed25519PrivateKey(keyData), nil
|
||||
}
|
||||
|
||||
func (ks *RouterInfoKeystore) GetKeys() (crypto.PublicKey, crypto.PrivateKey, error) {
|
||||
public, err := ks.privateKey.Public()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return public, ks.privateKey, nil
|
||||
}
|
||||
|
||||
func (ks *RouterInfoKeystore) StoreKeys() error {
|
||||
if _, err := os.Stat(ks.dir); os.IsNotExist(err) {
|
||||
err := os.MkdirAll(ks.dir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// on the disk somewhere
|
||||
filename := filepath.Join(ks.dir, ks.name)
|
||||
return os.WriteFile(filename, ks.privateKey.Bytes(), 0644)
|
||||
}
|
||||
|
||||
func (ks *RouterInfoKeystore) KeyID() string {
|
||||
if ks.name == "" {
|
||||
public, err := ks.privateKey.Public()
|
||||
if err != nil {
|
||||
return "error"
|
||||
}
|
||||
if len(public.Bytes()) > 10 {
|
||||
return string(public.Bytes()[:10])
|
||||
}
|
||||
return string(public.Bytes())
|
||||
}
|
||||
return ks.name
|
||||
}
|
67
lib/keys/types.go
Normal file
67
lib/keys/types.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
)
|
||||
|
||||
// KeyStore is an interface for storing and retrieving keys
|
||||
type KeyStore interface {
|
||||
KeyID() string
|
||||
// GetKeys returns the public and private keys
|
||||
GetKeys() (publicKey crypto.PublicKey, privateKey crypto.PrivateKey, err error)
|
||||
// StoreKeys stores the keys
|
||||
StoreKeys() error
|
||||
}
|
||||
|
||||
type KeyStoreImpl struct {
|
||||
dir string
|
||||
name string
|
||||
privateKey crypto.PrivateKey
|
||||
}
|
||||
|
||||
func NewKeyStoreImpl(dir, name string, privateKey crypto.PrivateKey) *KeyStoreImpl {
|
||||
return &KeyStoreImpl{
|
||||
dir: dir,
|
||||
name: name,
|
||||
privateKey: privateKey,
|
||||
}
|
||||
}
|
||||
|
||||
func (ks *KeyStoreImpl) KeyID() string {
|
||||
if ks.name == "" {
|
||||
public, err := ks.privateKey.Public()
|
||||
if err != nil {
|
||||
return "error"
|
||||
}
|
||||
if len(public.Bytes()) > 10 {
|
||||
return string(public.Bytes()[:10])
|
||||
} else {
|
||||
return string(public.Bytes())
|
||||
}
|
||||
}
|
||||
return ks.name
|
||||
}
|
||||
|
||||
func (ks *KeyStoreImpl) GetKeys() (crypto.PublicKey, crypto.PrivateKey, error) {
|
||||
public, err := ks.privateKey.Public()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return public, ks.privateKey, nil
|
||||
}
|
||||
|
||||
func (ks *KeyStoreImpl) StoreKeys() error {
|
||||
// make sure the directory exists
|
||||
if _, err := os.Stat(ks.dir); os.IsNotExist(err) {
|
||||
err := os.MkdirAll(ks.dir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// on the disk somewhere
|
||||
filename := fmt.Sprintf("private-%s.key", ks.KeyID())
|
||||
return os.WriteFile(filename, ks.privateKey.Bytes(), 0644)
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/logger"
|
||||
@@ -89,7 +90,7 @@ func (r *Router) mainloop() {
|
||||
log.WithError(err).Error("Failed to ensure NetDB")
|
||||
}
|
||||
if sz := r.ndb.Size(); sz >= 0 {
|
||||
log.WithField("size", sz).Debug("NetDB Size")
|
||||
log.WithField("size", sz).Debug("NetDB Size: " + strconv.Itoa(sz))
|
||||
} else {
|
||||
log.Warn("Unable to determine NetDB size")
|
||||
}
|
||||
|
22
lib/transport/obfs/doc.md
Normal file
22
lib/transport/obfs/doc.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# obfs
|
||||
--
|
||||
import "github.com/go-i2p/go-i2p/lib/transport/obfs"
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
#### func DeobfuscateEphemeralKey
|
||||
|
||||
```go
|
||||
func DeobfuscateEphemeralKey(message []byte, aesKey *crypto.AESSymmetricKey) ([]byte, error)
|
||||
```
|
||||
DeobfuscateEphemeralKey decrypts the ephemeral public key in the message using
|
||||
AES-256-CBC without padding
|
||||
|
||||
#### func ObfuscateEphemeralKey
|
||||
|
||||
```go
|
||||
func ObfuscateEphemeralKey(message []byte, aesKey *crypto.AESSymmetricKey) ([]byte, error)
|
||||
```
|
||||
ObfuscateEphemeralKey encrypts the ephemeral public key in the message using
|
||||
AES-256-CBC without padding
|
Reference in New Issue
Block a user