mirror of
https://github.com/go-i2p/go-i2p.git
synced 2025-08-18 23:45:25 -04:00
Compare commits
47 Commits
noise-expe
...
10k
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ddba94d6ae | ||
![]() |
767b91df49 | ||
![]() |
1292098cf0 | ||
![]() |
24bc4c3c17 | ||
![]() |
81eb270351 | ||
![]() |
b6f197cf92 | ||
![]() |
c10d98a3b2 | ||
![]() |
6d16ca5f87 | ||
![]() |
003d6c9ab8 | ||
![]() |
015c4b23e2 | ||
![]() |
e29c3c7abb | ||
![]() |
6f6291a9f6 | ||
![]() |
767864d457 | ||
![]() |
0a98236d85 | ||
![]() |
c1fa63f6ec | ||
![]() |
a75c275b4c | ||
![]() |
d40b3e0cd3 | ||
![]() |
2ee2d77d7c | ||
![]() |
271cf56ded | ||
![]() |
a29fa0bc03 | ||
![]() |
63c48dd3b7 | ||
![]() |
8bec47efd2 | ||
![]() |
69a50e2035 | ||
![]() |
8319444890 | ||
![]() |
b378661e0e | ||
![]() |
f4086e5f68 | ||
![]() |
877fc707c4 | ||
![]() |
98d05e27c8 | ||
![]() |
4020db8a19 | ||
![]() |
67a02f5d69 | ||
![]() |
ca1280231c | ||
![]() |
02b309df43 | ||
![]() |
a5b3c3f194 | ||
![]() |
0aa7a5554b | ||
![]() |
266a1b71d6 | ||
![]() |
d32f2e78ab | ||
![]() |
9e806bc32e | ||
![]() |
c52112a36f | ||
![]() |
db0fd9f7e9 | ||
![]() |
3ab258cde6 | ||
![]() |
20b9bbd8e4 | ||
![]() |
1fa520613c | ||
![]() |
fb99b98a7e | ||
![]() |
d6b8cd9d4d | ||
![]() |
92e4656774 | ||
![]() |
5f2bfb8d9d | ||
![]() |
9494c226a6 |
1
Makefile
1
Makefile
@@ -3,6 +3,7 @@ RELEASE_VERSION=${RELEASE_TAG}
|
||||
RELEASE_DESCRIPTION=`cat PASTA.md`
|
||||
REPO := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
CGO_ENABLED=0
|
||||
export DEBUG_I2P=debug
|
||||
|
||||
ifdef GOROOT
|
||||
GO = $(GOROOT)/bin/go
|
||||
|
18
PASTA.md
18
PASTA.md
@@ -1,18 +0,0 @@
|
||||
At long last... something useful
|
||||
================================
|
||||
|
||||
It's been 2 years of me mostly not having time to work on go-i2p itself since my last update.
|
||||
However, after much waiting, this library is actually **useful** for something.
|
||||
It is now being used in the `reseed-tools` application to examine RouterInfos prior to including them in reseed bundles.
|
||||
Routers that self-report as unreachable or congested will be excluded from future reseed bundles.
|
||||
Additionally, routers that self-report an old version will be excluded from reseed bundles.
|
||||
This should help new users build better connections faster with the existing, working router implementations.
|
||||
|
||||
This is not a working release of a go-i2p router
|
||||
------------------------------------------------
|
||||
|
||||
It is a numbered version of the go-i2p library, which is pre-release, expressly for use in the `reseed-tools` application.
|
||||
The common library works, and so do some of the cryptographic primitives, however the API is unstable and the software itself is certain to have serious bugs outside of a few well-tested areas.
|
||||
If you're using it for something other than parsing and analyzing RouterInfos and LeaseSets, you'll probably encounter bugs.
|
||||
Please report them to the https://github.com/go-i2p/go-i2p
|
||||
Use any part of it at your own risk.
|
@@ -41,7 +41,7 @@ please keep up with these changes, as they will not be backward compatible and r
|
||||
- [ ] Elligator2
|
||||
- [ ] HKDF
|
||||
- [ ] HMAC
|
||||
- [/] Noise subsystem
|
||||
- [X] Noise subsystem
|
||||
- End-to-End Crypto
|
||||
- [ ] Garlic messages
|
||||
- [ ] ElGamal/AES+SessionTag
|
||||
@@ -111,7 +111,7 @@ export DEBUG_I2P=warn
|
||||
export DEBUG_I2P=error
|
||||
```
|
||||
|
||||
If I2P_DEBUG is set to an unrecognized variable, it will fall back to "debug".
|
||||
If DEBUG_I2P is set to an unrecognized variable, it will fall back to "debug".
|
||||
|
||||
## Contributing
|
||||
|
||||
|
41
ROADMAP.md
Normal file
41
ROADMAP.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# go-i2p Implementation Roadmap
|
||||
|
||||
## Transport Layer (NTCP2)
|
||||
- Build on existing lib/transport/noise implementation
|
||||
- Core NTCP2 components:
|
||||
* Session handshake using noise protocol
|
||||
* Connection management
|
||||
* I2NP message transport
|
||||
|
||||
## Reseed System
|
||||
- SU3 file format implementation:
|
||||
* Format parsing and validation(Much of this work is done in reseed-tools, may need to be moved here)
|
||||
* Signature verification system(Much of this work is done in reseed-tools, may need to be moved here)
|
||||
- Local reseed functionality:
|
||||
* File-based reseed operations
|
||||
- Self-signed/Package-pinned X.509 certificate handling for reseed validation
|
||||
|
||||
## NetDb and Database Store
|
||||
- Database Store message handling:
|
||||
* Message structure implementation
|
||||
* Message handling implementation
|
||||
- NetDb core implementation:
|
||||
* RouterInfo management
|
||||
* LeaseSet management
|
||||
* Lookup system
|
||||
* Storage interface
|
||||
* Peer selection logic?(Maybe do something very basic for now like i2pd used to do, and then improve it later, the important part will be interface design at first)
|
||||
|
||||
## Tunnel Implementation
|
||||
- Tunnel cryptography:
|
||||
* Key generation and management
|
||||
* Layered encryption scheme
|
||||
- Message processing:
|
||||
* Build request/response handling
|
||||
* Gateway implementation
|
||||
* Message forwarding logic
|
||||
|
||||
Notes:
|
||||
- Excluding legacy protocols (SSU1, NTCP1, elgamal, DSA)
|
||||
- Leveraging existing noise protocol implementation
|
||||
- SSU2 is not on this roadmap but is fair game for implementation as soon as NTCP2 is done. We're focused on NTCP2 to get this thing sending I2NP messages.
|
@@ -1,15 +1,15 @@
|
||||
test-crypto-aes-all: test-crypto-aes-core test-crypto-aes-validation test-crypto-aes-padding
|
||||
|
||||
test-crypto-aes-core:
|
||||
go test -v ./lib/crypto -run TestAESEncryptDecrypt
|
||||
$(GO) test -v ./lib/crypto -run TestAESEncryptDecrypt
|
||||
|
||||
test-crypto-aes-validation:
|
||||
go test -v ./lib/crypto -run TestAESEncryptInvalidKey
|
||||
go test -v ./lib/crypto -run TestAESDecryptInvalidInput
|
||||
$(GO) test -v ./lib/crypto -run TestAESEncryptInvalidKey
|
||||
$(GO) test -v ./lib/crypto -run TestAESDecryptInvalidInput
|
||||
|
||||
test-crypto-aes-padding:
|
||||
go test -v ./lib/crypto -run TestPKCS7PadUnpad
|
||||
go test -v ./lib/crypto -run TestPKCS7UnpadInvalidInput
|
||||
$(GO) test -v ./lib/crypto -run TestPKCS7PadUnpad
|
||||
$(GO) test -v ./lib/crypto -run TestPKCS7UnpadInvalidInput
|
||||
|
||||
.PHONY: test-crypto-aes-all \
|
||||
test-crypto-aes-core \
|
||||
|
@@ -1,4 +1,4 @@
|
||||
test-base32-encode-decode-not-mangled:
|
||||
go test -v ./lib/common/base32 -run TestEncodeDecodeNotMangled
|
||||
$(GO) test -v ./lib/common/base32 -run TestEncodeDecodeNotMangled
|
||||
|
||||
.PHONY: test-base32-encode-decode-not-mangled
|
@@ -1,4 +1,4 @@
|
||||
test-base64-encode-decode-not-mangled:
|
||||
go test -v ./lib/common/base64 -run TestEncodeDecodeNotMangled
|
||||
$(GO) test -v ./lib/common/base64 -run TestEncodeDecodeNotMangled
|
||||
|
||||
.PHONY: test-base64-encode-decode-not-mangled
|
@@ -1,22 +1,22 @@
|
||||
test-build-request-all: test-build-request-receive test-build-request-ident test-build-request-components
|
||||
|
||||
test-build-request-receive:
|
||||
go test -v ./lib/i2np -run TestReadBuildRequestRecordReceiveTunnel
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordReceiveTunnel
|
||||
|
||||
test-build-request-ident:
|
||||
go test -v ./lib/i2np -run TestReadBuildRequestRecordOurIdent
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordOurIdent
|
||||
|
||||
test-build-request-components:
|
||||
go test -v ./lib/i2np -run TestReadBuildRequestRecordNextTunnel
|
||||
go test -v ./lib/i2np -run TestReadBuildRequestRecordNextIdent
|
||||
go test -v ./lib/i2np -run TestReadBuildRequestRecordLayerKey
|
||||
go test -v ./lib/i2np -run TestReadBuildRequestRecordIVKey
|
||||
go test -v ./lib/i2np -run TestReadBuildRequestRecordReplyKey
|
||||
go test -v ./lib/i2np -run TestReadBuildRequestRecordReplyIV
|
||||
go test -v ./lib/i2np -run TestReadBuildRequestRecordFlag
|
||||
go test -v ./lib/i2np -run TestReadBuildRequestRecordRequestTime
|
||||
go test -v ./lib/i2np -run TestReadBuildRequestRecordSendMessageID
|
||||
go test -v ./lib/i2np -run TestReadBuildRequestRecordPadding
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordNextTunnel
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordNextIdent
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordLayerKey
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordIVKey
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordReplyKey
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordReplyIV
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordFlag
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordRequestTime
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordSendMessageID
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordPadding
|
||||
|
||||
.PHONY: test-build-request-all \
|
||||
test-build-request-receive \
|
||||
|
@@ -2,46 +2,46 @@
|
||||
test-cert-all: test-cert-type test-cert-length test-cert-data test-cert-read test-cert-length-correct test-cert-length-too-short test-cert-length-data-short test-cert-data-correct test-cert-data-too-long test-cert-data-too-short test-cert-read-correct test-cert-read-short test-cert-read-remainder test-cert-read-invalid
|
||||
|
||||
test-cert-type:
|
||||
go test -v ./lib/common/certificate -run TestCertificateTypeIsFirstByte
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateTypeIsFirstByte
|
||||
|
||||
test-cert-length:
|
||||
go test -v ./lib/common/certificate -run TestCertificateLength
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateLength
|
||||
|
||||
test-cert-data:
|
||||
go test -v ./lib/common/certificate -run TestCertificateData
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateData
|
||||
|
||||
test-cert-read:
|
||||
go test -v ./lib/common/certificate -run TestReadCertificate
|
||||
$(GO) test -v ./lib/common/certificate -run TestReadCertificate
|
||||
|
||||
test-cert-length-correct:
|
||||
go test -v ./lib/common/certificate -run TestCertificateLengthCorrect
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateLengthCorrect
|
||||
|
||||
test-cert-length-too-short:
|
||||
go test -v ./lib/common/certificate -run TestCertificateLengthErrWhenTooShort
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateLengthErrWhenTooShort
|
||||
|
||||
test-cert-length-data-short:
|
||||
go test -v ./lib/common/certificate -run TestCertificateLengthErrWhenDataTooShort
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateLengthErrWhenDataTooShort
|
||||
|
||||
test-cert-data-correct:
|
||||
go test -v ./lib/common/certificate -run TestCertificateDataWhenCorrectSize
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateDataWhenCorrectSize
|
||||
|
||||
test-cert-data-too-long:
|
||||
go test -v ./lib/common/certificate -run TestCertificateDataWhenTooLong
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateDataWhenTooLong
|
||||
|
||||
test-cert-data-too-short:
|
||||
go test -v ./lib/common/certificate -run TestCertificateDataWhenTooShort
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateDataWhenTooShort
|
||||
|
||||
test-cert-read-correct:
|
||||
go test -v ./lib/common/certificate -run TestReadCertificateWithCorrectData
|
||||
$(GO) test -v ./lib/common/certificate -run TestReadCertificateWithCorrectData
|
||||
|
||||
test-cert-read-short:
|
||||
go test -v ./lib/common/certificate -run TestReadCertificateWithDataTooShort
|
||||
$(GO) test -v ./lib/common/certificate -run TestReadCertificateWithDataTooShort
|
||||
|
||||
test-cert-read-remainder:
|
||||
go test -v ./lib/common/certificate -run TestReadCertificateWithRemainder
|
||||
$(GO) test -v ./lib/common/certificate -run TestReadCertificateWithRemainder
|
||||
|
||||
test-cert-read-invalid:
|
||||
go test -v ./lib/common/certificate -run TestReadCertificateWithInvalidLength
|
||||
$(GO) test -v ./lib/common/certificate -run TestReadCertificateWithInvalidLength
|
||||
|
||||
# Declare all targets as PHONY
|
||||
.PHONY: test-cert-all \
|
||||
|
@@ -1,2 +1,2 @@
|
||||
test-date-time-from-milliseconds:
|
||||
go test -v ./lib/common/data -run TestTimeFromMilliseconds
|
||||
$(GO) test -v ./lib/common/data -run TestTimeFromMilliseconds
|
@@ -1,17 +1,17 @@
|
||||
test-crypto-dsa-all: test-crypto-dsa test-crypto-dsa-benchmarks
|
||||
|
||||
test-crypto-dsa:
|
||||
go test -v ./lib/crypto -run TestDSA
|
||||
$(GO) test -v ./lib/crypto -run TestDSA
|
||||
|
||||
test-crypto-dsa-benchmarks:
|
||||
go test -v ./lib/crypto -bench=DSA -run=^$
|
||||
$(GO) test -v ./lib/crypto -bench=DSA -run=^$
|
||||
|
||||
# Individual benchmarks
|
||||
test-crypto-dsa-bench-generate:
|
||||
go test -v ./lib/crypto -bench=DSAGenerate -run=^$
|
||||
$(GO) test -v ./lib/crypto -bench=DSAGenerate -run=^$
|
||||
|
||||
test-crypto-dsa-bench-sign-verify:
|
||||
go test -v ./lib/crypto -bench=DSASignVerify -run=^$
|
||||
$(GO) test -v ./lib/crypto -bench=DSASignVerify -run=^$
|
||||
|
||||
.PHONY: test-crypto-dsa-all \
|
||||
test-crypto-dsa \
|
||||
|
@@ -1,7 +1,7 @@
|
||||
test-crypto-ed25519-all: test-crypto-ed25519
|
||||
|
||||
test-crypto-ed25519:
|
||||
go test -v ./lib/crypto -run TestEd25519
|
||||
$(GO) test -v ./lib/crypto -run TestEd25519
|
||||
|
||||
.PHONY: test-crypto-ed25519-all \
|
||||
test-crypto-ed25519
|
||||
|
@@ -1,20 +1,20 @@
|
||||
test-crypto-elg-all: test-crypto-elg test-crypto-elg-benchmarks
|
||||
|
||||
test-crypto-elg:
|
||||
go test -v ./lib/crypto -run TestElg
|
||||
$(GO) test -v ./lib/crypto -run TestElg
|
||||
|
||||
test-crypto-elg-benchmarks:
|
||||
go test -v ./lib/crypto -bench=Elg -run=^$
|
||||
$(GO) test -v ./lib/crypto -bench=Elg -run=^$
|
||||
|
||||
# Individual benchmarks
|
||||
test-crypto-elg-bench-generate:
|
||||
go test -v ./lib/crypto -bench=ElgGenerate -run=^$
|
||||
$(GO) test -v ./lib/crypto -bench=ElgGenerate -run=^$
|
||||
|
||||
test-crypto-elg-bench-encrypt:
|
||||
go test -v ./lib/crypto -bench=ElgEncrypt -run=^$
|
||||
$(GO) test -v ./lib/crypto -bench=ElgEncrypt -run=^$
|
||||
|
||||
test-crypto-elg-bench-decrypt:
|
||||
go test -v ./lib/crypto -bench=ElgDecrypt -run=^$
|
||||
$(GO) test -v ./lib/crypto -bench=ElgDecrypt -run=^$
|
||||
|
||||
.PHONY: test-crypto-elg-all \
|
||||
test-crypto-elg \
|
||||
|
@@ -2,24 +2,24 @@
|
||||
test-i2np-header-all: test-i2np-type test-i2np-message test-i2np-expiration test-i2np-ntcp-components test-i2np-data test-i2np-regression
|
||||
|
||||
test-i2np-type:
|
||||
go test -v ./lib/i2np -run TestReadI2NPTypeWith
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPTypeWith
|
||||
|
||||
test-i2np-message:
|
||||
go test -v ./lib/i2np -run TestReadI2NPNTCPMessageID
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPMessageID
|
||||
|
||||
test-i2np-expiration:
|
||||
go test -v ./lib/i2np -run TestReadI2NPNTCPMessageExpiration
|
||||
go test -v ./lib/i2np -run TestReadI2NPSSUMessageExpiration
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPMessageExpiration
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPSSUMessageExpiration
|
||||
|
||||
test-i2np-ntcp-components:
|
||||
go test -v ./lib/i2np -run TestReadI2NPNTCPMessageSize
|
||||
go test -v ./lib/i2np -run TestReadI2NPNTCPMessageChecksum
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPMessageSize
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPMessageChecksum
|
||||
|
||||
test-i2np-data:
|
||||
go test -v ./lib/i2np -run TestReadI2NPNTCPData
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPData
|
||||
|
||||
test-i2np-regression:
|
||||
go test -v ./lib/i2np -run TestCrasherRegression123781
|
||||
$(GO) test -v ./lib/i2np -run TestCrasherRegression123781
|
||||
|
||||
.PHONY: test-i2np-header-all \
|
||||
test-i2np-type \
|
||||
|
@@ -1,7 +1,7 @@
|
||||
test-crypto-hmac-all: test-crypto-hmac
|
||||
|
||||
test-crypto-hmac:
|
||||
go test -v ./lib/crypto -run Test_I2PHMAC
|
||||
$(GO) test -v ./lib/crypto -run Test_I2PHMAC
|
||||
|
||||
.PHONY: test-crypto-hmac-all \
|
||||
test-crypto-hmac
|
||||
|
@@ -1,13 +1,13 @@
|
||||
test-integer-all: test-integer-big-endian test-integer-one-byte test-integer-zero
|
||||
|
||||
test-integer-big-endian:
|
||||
go test -v ./lib/common/integer -run TestIntegerBigEndian
|
||||
$(GO) test -v ./lib/common/integer -run TestIntegerBigEndian
|
||||
|
||||
test-integer-one-byte:
|
||||
go test -v ./lib/common/integer -run TestWorksWithOneByte
|
||||
$(GO) test -v ./lib/common/integer -run TestWorksWithOneByte
|
||||
|
||||
test-integer-zero:
|
||||
go test -v ./lib/common/integer -run TestIsZeroWithNoData
|
||||
$(GO) test -v ./lib/common/integer -run TestIsZeroWithNoData
|
||||
|
||||
.PHONY: test-integer-all \
|
||||
test-integer-big-endian \
|
||||
|
@@ -1,21 +1,21 @@
|
||||
test-key-cert-all: test-key-cert-signing test-key-cert-public test-key-cert-construct
|
||||
|
||||
test-key-cert-signing:
|
||||
go test -v ./lib/common/key_certificate -run TestSingingPublicKeyTypeReturnsCorrectInteger
|
||||
go test -v ./lib/common/key_certificate -run TestSingingPublicKeyTypeReportsWhenDataTooSmall
|
||||
go test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyReportsWhenDataTooSmall
|
||||
go test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithDSASHA1
|
||||
go test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP256
|
||||
go test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP384
|
||||
go test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP521
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestSingingPublicKeyTypeReturnsCorrectInteger
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestSingingPublicKeyTypeReportsWhenDataTooSmall
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyReportsWhenDataTooSmall
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithDSASHA1
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP256
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP384
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP521
|
||||
|
||||
test-key-cert-public:
|
||||
go test -v ./lib/common/key_certificate -run TestPublicKeyTypeReturnsCorrectInteger
|
||||
go test -v ./lib/common/key_certificate -run TestPublicKeyTypeReportsWhenDataTooSmall
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestPublicKeyTypeReturnsCorrectInteger
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestPublicKeyTypeReportsWhenDataTooSmall
|
||||
|
||||
test-key-cert-construct:
|
||||
go test -v ./lib/common/key_certificate -run TestConstructPublicKeyReportsWhenDataTooSmall
|
||||
go test -v ./lib/common/key_certificate -run TestConstructPublicKeyReturnsCorrectDataWithElg
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructPublicKeyReportsWhenDataTooSmall
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructPublicKeyReturnsCorrectDataWithElg
|
||||
|
||||
.PHONY: test-key-cert-all \
|
||||
test-key-cert-signing \
|
||||
|
@@ -1,27 +1,27 @@
|
||||
test-keys-cert-all: test-keys-cert-certificate test-keys-cert-public test-keys-cert-signing test-keys-cert-creation
|
||||
|
||||
test-keys-cert-certificate:
|
||||
go test -v ./lib/common/keys_and_cert -run TestCertificateWithValidData
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestCertificateWithValidData
|
||||
|
||||
test-keys-cert-public:
|
||||
go test -v ./lib/common/keys_and_cert -run TestPublicKeyWithBadData
|
||||
go test -v ./lib/common/keys_and_cert -run TestPublicKeyWithBadCertificate
|
||||
go test -v ./lib/common/keys_and_cert -run TestPublicKeyWithNullCertificate
|
||||
go test -v ./lib/common/keys_and_cert -run TestPublicKeyWithKeyCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestPublicKeyWithBadData
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestPublicKeyWithBadCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestPublicKeyWithNullCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestPublicKeyWithKeyCertificate
|
||||
|
||||
test-keys-cert-signing:
|
||||
go test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithBadData
|
||||
go test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithBadCertificate
|
||||
go test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithNullCertificate
|
||||
go test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithKeyCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithBadData
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithBadCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithNullCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithKeyCertificate
|
||||
|
||||
test-keys-cert-creation:
|
||||
go test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithMissingData
|
||||
go test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithMissingCertData
|
||||
go test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithCertificate
|
||||
go test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithoutCertificate
|
||||
go test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithCertificateAndRemainder
|
||||
go test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithoutCertificateAndRemainder
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithMissingData
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithMissingCertData
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithoutCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithCertificateAndRemainder
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithoutCertificateAndRemainder
|
||||
|
||||
.PHONY: test-keys-cert-all \
|
||||
test-keys-cert-certificate \
|
||||
|
@@ -1,20 +1,20 @@
|
||||
test-lease-set-all: test-lease-set-basic test-lease-set-leases test-lease-set-expiration
|
||||
|
||||
test-lease-set-basic:
|
||||
go test -v ./lib/common/lease_set -run TestDestinationIsCorrect
|
||||
go test -v ./lib/common/lease_set -run TestPublicKeyIsCorrect
|
||||
go test -v ./lib/common/lease_set -run TestSigningKeyIsCorrect
|
||||
go test -v ./lib/common/lease_set -run TestSignatureIsCorrect
|
||||
$(GO) test -v ./lib/common/lease_set -run TestDestinationIsCorrect
|
||||
$(GO) test -v ./lib/common/lease_set -run TestPublicKeyIsCorrect
|
||||
$(GO) test -v ./lib/common/lease_set -run TestSigningKeyIsCorrect
|
||||
$(GO) test -v ./lib/common/lease_set -run TestSignatureIsCorrect
|
||||
|
||||
test-lease-set-leases:
|
||||
go test -v ./lib/common/lease_set -run TestLeaseCountCorrect
|
||||
go test -v ./lib/common/lease_set -run TestLeaseCountCorrectWithMultiple
|
||||
go test -v ./lib/common/lease_set -run TestLeaseCountErrorWithTooMany
|
||||
go test -v ./lib/common/lease_set -run TestLeasesHaveCorrectData
|
||||
$(GO) test -v ./lib/common/lease_set -run TestLeaseCountCorrect
|
||||
$(GO) test -v ./lib/common/lease_set -run TestLeaseCountCorrectWithMultiple
|
||||
$(GO) test -v ./lib/common/lease_set -run TestLeaseCountErrorWithTooMany
|
||||
$(GO) test -v ./lib/common/lease_set -run TestLeasesHaveCorrectData
|
||||
|
||||
test-lease-set-expiration:
|
||||
go test -v ./lib/common/lease_set -run TestNewestExpirationIsCorrect
|
||||
go test -v ./lib/common/lease_set -run TestOldestExpirationIsCorrect
|
||||
$(GO) test -v ./lib/common/lease_set -run TestNewestExpirationIsCorrect
|
||||
$(GO) test -v ./lib/common/lease_set -run TestOldestExpirationIsCorrect
|
||||
|
||||
.PHONY: test-lease-set-all \
|
||||
test-lease-set-basic \
|
||||
|
@@ -1,25 +1,25 @@
|
||||
test-mapping-all: test-mapping-values test-mapping-duplicates test-mapping-conversion test-mapping-utils
|
||||
|
||||
test-mapping-values:
|
||||
go test -v ./lib/common/data -run TestValuesExclusesPairWithBadData
|
||||
go test -v ./lib/common/data -run TestValuesWarnsMissingData
|
||||
go test -v ./lib/common/data -run TestValuesWarnsExtraData
|
||||
go test -v ./lib/common/data -run TestValuesEnforcesEqualDelimitor
|
||||
go test -v ./lib/common/data -run TestValuesEnforcedSemicolonDelimitor
|
||||
go test -v ./lib/common/data -run TestValuesReturnsValues
|
||||
$(GO) test -v ./lib/common/data -run TestValuesExclusesPairWithBadData
|
||||
$(GO) test -v ./lib/common/data -run TestValuesWarnsMissingData
|
||||
$(GO) test -v ./lib/common/data -run TestValuesWarnsExtraData
|
||||
$(GO) test -v ./lib/common/data -run TestValuesEnforcesEqualDelimitor
|
||||
$(GO) test -v ./lib/common/data -run TestValuesEnforcedSemicolonDelimitor
|
||||
$(GO) test -v ./lib/common/data -run TestValuesReturnsValues
|
||||
|
||||
test-mapping-duplicates:
|
||||
go test -v ./lib/common/data -run TestHasDuplicateKeysTrueWhenDuplicates
|
||||
go test -v ./lib/common/data -run TestHasDuplicateKeysFalseWithoutDuplicates
|
||||
go test -v ./lib/common/data -run TestReadMappingHasDuplicateKeys
|
||||
$(GO) test -v ./lib/common/data -run TestHasDuplicateKeysTrueWhenDuplicates
|
||||
$(GO) test -v ./lib/common/data -run TestHasDuplicateKeysFalseWithoutDuplicates
|
||||
$(GO) test -v ./lib/common/data -run TestReadMappingHasDuplicateKeys
|
||||
|
||||
test-mapping-conversion:
|
||||
go test -v ./lib/common/data -run TestGoMapToMappingProducesCorrectMapping
|
||||
go test -v ./lib/common/data -run TestFullGoMapToMappingProducesCorrectMapping
|
||||
$(GO) test -v ./lib/common/data -run TestGoMapToMappingProducesCorrectMapping
|
||||
$(GO) test -v ./lib/common/data -run TestFullGoMapToMappingProducesCorrectMapping
|
||||
|
||||
test-mapping-utils:
|
||||
go test -v ./lib/common/data -run TestStopValueRead
|
||||
go test -v ./lib/common/data -run TestBeginsWith
|
||||
$(GO) test -v ./lib/common/data -run TestStopValueRead
|
||||
$(GO) test -v ./lib/common/data -run TestBeginsWith
|
||||
|
||||
.PHONY: test-mapping-all \
|
||||
test-mapping-values \
|
||||
|
@@ -1,2 +1,2 @@
|
||||
test-mapping-values-order:
|
||||
go test -v ./lib/common/data -run TestMappingOrderSortsValuesThenKeys
|
||||
$(GO) test -v ./lib/common/data -run TestMappingOrderSortsValuesThenKeys
|
@@ -1,16 +1,16 @@
|
||||
test-noise-transport-all: test-noise-packet-encryption test-noise-transport-connection test-noise-packet-obfuscation test-noise-packet-obfuscation-func
|
||||
|
||||
test-noise-packet-encryption:
|
||||
go test -v ./lib/transport/noise -run TestEncryptDecryptPacketOffline
|
||||
$(GO) test -v ./lib/transport/noise -run TestEncryptDecryptPacketOffline
|
||||
|
||||
test-noise-transport-connection:
|
||||
go test -v ./lib/transport/noise -run TestTransport
|
||||
$(GO) test -v ./lib/transport/noise -run TestTransport
|
||||
|
||||
test-noise-packet-obfuscation:
|
||||
go test -v ./lib/transport/noise -run TestEncryptDecryptPacketObfsOffline
|
||||
$(GO) test -v ./lib/transport/noise -run TestEncryptDecryptPacketObfsOffline
|
||||
|
||||
test-noise-packet-obfuscation-func:
|
||||
go test -v ./lib/transport/noise -run TestEncryptDecryptPacketObfsOfflineWithFunc
|
||||
$(GO) test -v ./lib/transport/noise -run TestEncryptDecryptPacketObfsOfflineWithFunc
|
||||
|
||||
.PHONY: test-noise-transport-all \
|
||||
test-noise-packet-encryption \
|
||||
|
@@ -1,17 +1,17 @@
|
||||
test-router-address-all: test-router-address-validation test-router-address-functionality test-router-address-fuzz
|
||||
|
||||
test-router-address-validation:
|
||||
go test -v ./lib/common/router_address -run TestCheckValidReportsEmptySlice
|
||||
go test -v ./lib/common/router_address -run TestCheckRouterAddressValidReportsDataMissing
|
||||
go test -v ./lib/common/router_address -run TestCheckRouterAddressValidNoErrWithValidData
|
||||
$(GO) test -v ./lib/common/router_address -run TestCheckValidReportsEmptySlice
|
||||
$(GO) test -v ./lib/common/router_address -run TestCheckRouterAddressValidReportsDataMissing
|
||||
$(GO) test -v ./lib/common/router_address -run TestCheckRouterAddressValidNoErrWithValidData
|
||||
|
||||
test-router-address-functionality:
|
||||
go test -v ./lib/common/router_address -run TestRouterAddressCostReturnsFirstByte
|
||||
go test -v ./lib/common/router_address -run TestRouterAddressExpirationReturnsCorrectData
|
||||
go test -v ./lib/common/router_address -run TestReadRouterAddressReturnsCorrectRemainderWithoutError
|
||||
$(GO) test -v ./lib/common/router_address -run TestRouterAddressCostReturnsFirstByte
|
||||
$(GO) test -v ./lib/common/router_address -run TestRouterAddressExpirationReturnsCorrectData
|
||||
$(GO) test -v ./lib/common/router_address -run TestReadRouterAddressReturnsCorrectRemainderWithoutError
|
||||
|
||||
test-router-address-fuzz:
|
||||
go test -v ./lib/common/router_address -run TestCorrectsFuzzCrasher1
|
||||
$(GO) test -v ./lib/common/router_address -run TestCorrectsFuzzCrasher1
|
||||
|
||||
.PHONY: test-router-address-all \
|
||||
test-router-address-validation \
|
||||
|
@@ -1,23 +1,23 @@
|
||||
test-router-info-all: test-router-info-published test-router-info-addresses test-router-info-identity test-router-info-misc
|
||||
|
||||
test-router-info-published:
|
||||
go test -v ./lib/common/router_info -run TestPublishedReturnsCorrectDate
|
||||
go test -v ./lib/common/router_info -run TestPublishedReturnsCorrectErrorWithPartialDate
|
||||
go test -v ./lib/common/router_info -run TestPublishedReturnsCorrectErrorWithInvalidData
|
||||
$(GO) test -v ./lib/common/router_info -run TestPublishedReturnsCorrectDate
|
||||
$(GO) test -v ./lib/common/router_info -run TestPublishedReturnsCorrectErrorWithPartialDate
|
||||
$(GO) test -v ./lib/common/router_info -run TestPublishedReturnsCorrectErrorWithInvalidData
|
||||
|
||||
test-router-info-addresses:
|
||||
go test -v ./lib/common/router_info -run TestRouterAddressCountReturnsCorrectCount
|
||||
go test -v ./lib/common/router_info -run TestRouterAddressCountReturnsCorrectErrorWithInvalidData
|
||||
go test -v ./lib/common/router_info -run TestRouterAddressesReturnsAddresses
|
||||
go test -v ./lib/common/router_info -run TestRouterAddressesReturnsAddressesWithMultiple
|
||||
$(GO) test -v ./lib/common/router_info -run TestRouterAddressCountReturnsCorrectCount
|
||||
$(GO) test -v ./lib/common/router_info -run TestRouterAddressCountReturnsCorrectErrorWithInvalidData
|
||||
$(GO) test -v ./lib/common/router_info -run TestRouterAddressesReturnsAddresses
|
||||
$(GO) test -v ./lib/common/router_info -run TestRouterAddressesReturnsAddressesWithMultiple
|
||||
|
||||
test-router-info-identity:
|
||||
go test -v ./lib/common/router_info -run TestRouterIdentityIsCorrect
|
||||
$(GO) test -v ./lib/common/router_info -run TestRouterIdentityIsCorrect
|
||||
|
||||
test-router-info-misc:
|
||||
go test -v ./lib/common/router_info -run TestPeerSizeIsZero
|
||||
go test -v ./lib/common/router_info -run TestOptionsAreCorrect
|
||||
go test -v ./lib/common/router_info -run TestSignatureIsCorrectSize
|
||||
$(GO) test -v ./lib/common/router_info -run TestPeerSizeIsZero
|
||||
$(GO) test -v ./lib/common/router_info -run TestOptionsAreCorrect
|
||||
$(GO) test -v ./lib/common/router_info -run TestSignatureIsCorrectSize
|
||||
|
||||
.PHONY: test-router-info-all \
|
||||
test-router-info-published \
|
||||
|
@@ -1,24 +1,24 @@
|
||||
test-string-all: test-string-length test-string-data test-string-conversion test-string-read
|
||||
|
||||
test-string-length:
|
||||
go test -v ./lib/common/data -run TestStringReportsCorrectLength
|
||||
go test -v ./lib/common/data -run TestI2PStringReportsLengthZeroError
|
||||
go test -v ./lib/common/data -run TestI2PStringReportsExtraDataError
|
||||
go test -v ./lib/common/data -run TestI2PStringDataReportsLengthZeroError
|
||||
$(GO) test -v ./lib/common/data -run TestStringReportsCorrectLength
|
||||
$(GO) test -v ./lib/common/data -run TestI2PStringReportsLengthZeroError
|
||||
$(GO) test -v ./lib/common/data -run TestI2PStringReportsExtraDataError
|
||||
$(GO) test -v ./lib/common/data -run TestI2PStringDataReportsLengthZeroError
|
||||
|
||||
test-string-data:
|
||||
go test -v ./lib/common/data -run TestI2PStringDataReportsExtraDataError
|
||||
go test -v ./lib/common/data -run TestI2PStringDataEmptyWhenZeroLength
|
||||
go test -v ./lib/common/data -run TestI2PStringDataErrorWhenNonZeroLengthOnly
|
||||
$(GO) test -v ./lib/common/data -run TestI2PStringDataReportsExtraDataError
|
||||
$(GO) test -v ./lib/common/data -run TestI2PStringDataEmptyWhenZeroLength
|
||||
$(GO) test -v ./lib/common/data -run TestI2PStringDataErrorWhenNonZeroLengthOnly
|
||||
|
||||
test-string-conversion:
|
||||
go test -v ./lib/common/data -run TestToI2PI2PStringFormatsCorrectly
|
||||
go test -v ./lib/common/data -run TestToI2PStringReportsOverflows
|
||||
$(GO) test -v ./lib/common/data -run TestToI2PI2PStringFormatsCorrectly
|
||||
$(GO) test -v ./lib/common/data -run TestToI2PStringReportsOverflows
|
||||
|
||||
test-string-read:
|
||||
go test -v ./lib/common/data -run TestReadStringReadsLength
|
||||
go test -v ./lib/common/data -run TestReadI2PStringErrWhenEmptySlice
|
||||
go test -v ./lib/common/data -run TestReadI2PStringErrWhenDataTooShort
|
||||
$(GO) test -v ./lib/common/data -run TestReadStringReadsLength
|
||||
$(GO) test -v ./lib/common/data -run TestReadI2PStringErrWhenEmptySlice
|
||||
$(GO) test -v ./lib/common/data -run TestReadI2PStringErrWhenDataTooShort
|
||||
|
||||
.PHONY: test-string-all \
|
||||
test-string-length \
|
||||
|
@@ -1,10 +1,10 @@
|
||||
test-su3-all: test-su3-read test-su3-signature
|
||||
|
||||
test-su3-read:
|
||||
go test -v ./lib/su3 -run TestRead
|
||||
$(GO) test -v ./lib/su3 -run TestRead
|
||||
|
||||
test-su3-signature:
|
||||
go test -v ./lib/su3 -run TestReadSignatureFirst
|
||||
$(GO) test -v ./lib/su3 -run TestReadSignatureFirst
|
||||
|
||||
.PHONY: test-su3-all \
|
||||
test-su3-read \
|
||||
|
@@ -2,18 +2,18 @@ test-tunnel-all: test-tunnel-delivery-instructions test-tunnel-message
|
||||
|
||||
# Tests from delivery_test.go
|
||||
test-tunnel-delivery-instructions:
|
||||
go test -v ./lib/tunnel -run TestReadDeliveryInstructions
|
||||
$(GO) test -v ./lib/tunnel -run TestReadDeliveryInstructions
|
||||
|
||||
# Tests from message_test.go
|
||||
test-tunnel-message: test-tunnel-message-padding test-tunnel-message-fragments
|
||||
|
||||
test-tunnel-message-padding:
|
||||
go test -v ./lib/tunnel -run TestDeliveryInstructionDataWithNoPadding
|
||||
go test -v ./lib/tunnel -run TestDeliveryInstructionDataWithSomePadding
|
||||
go test -v ./lib/tunnel -run TestDeliveryInstructionDataWithOnlyPadding
|
||||
$(GO) test -v ./lib/tunnel -run TestDeliveryInstructionDataWithNoPadding
|
||||
$(GO) test -v ./lib/tunnel -run TestDeliveryInstructionDataWithSomePadding
|
||||
$(GO) test -v ./lib/tunnel -run TestDeliveryInstructionDataWithOnlyPadding
|
||||
|
||||
test-tunnel-message-fragments:
|
||||
go test -v ./lib/tunnel -run TestDeliveryInstructionsWithFragments
|
||||
$(GO) test -v ./lib/tunnel -run TestDeliveryInstructionsWithFragments
|
||||
|
||||
.PHONY: test-tunnel-all \
|
||||
test-tunnel-delivery-instructions \
|
||||
|
13
go.mod
13
go.mod
@@ -3,14 +3,17 @@ module github.com/go-i2p/go-i2p
|
||||
go 1.23.1
|
||||
|
||||
require (
|
||||
github.com/emirpasic/gods v1.18.1
|
||||
github.com/beevik/ntp v1.4.3
|
||||
github.com/emirpasic/gods v1.18.1
|
||||
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e
|
||||
github.com/flynn/noise v1.1.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
go.step.sm/crypto v0.53.0
|
||||
golang.org/x/crypto v0.27.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -28,19 +31,13 @@ require (
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.7.0 // indirect
|
||||
github.com/spf13/cobra v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.19.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/net v0.29.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/text v0.18.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/net v0.28.0 // indirect
|
||||
golang.org/x/sys v0.24.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
20
go.sum
20
go.sum
@@ -1,10 +1,9 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho=
|
||||
github.com/beevik/ntp v1.4.3/go.mod h1:Unr8Zg+2dRn7d8bHFuehIMSvvUYssHMxW3Q5Nx4RW5Q=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -14,27 +13,34 @@ github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e h1:NMjWYVkgcQHG
|
||||
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e/go.mod h1:fKfFM3BsOOyjtZmEty7FsGzGabXo8Eb/dHjyIhTtxsE=
|
||||
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
|
||||
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
@@ -79,8 +85,8 @@ golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt7
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
|
@@ -3,6 +3,8 @@
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -143,9 +145,9 @@ func (c *Certificate) Data() (data []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
// NewCertificate creates a new Certficiate from []byte
|
||||
// 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 NewCertificate(data []byte) (certificate Certificate, err error) {
|
||||
func readCertificate(data []byte) (certificate Certificate, err error) {
|
||||
certificate = Certificate{}
|
||||
switch len(data) {
|
||||
case 0:
|
||||
@@ -171,14 +173,14 @@ func NewCertificate(data []byte) (certificate Certificate, err error) {
|
||||
default:
|
||||
certificate.kind = Integer(data[0:1])
|
||||
certificate.len = Integer(data[1:3])
|
||||
payleng := len(data) - CERT_MIN_SIZE
|
||||
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")
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Certificate) NewCertificate",
|
||||
"certificate_bytes_length": certificate.len.Int(),
|
||||
"certificate_payload_length": payleng,
|
||||
"certificate_payload_length": payloadLength,
|
||||
"data_bytes:": string(data),
|
||||
"kind_bytes": data[0:1],
|
||||
"len_bytes": data[1:3],
|
||||
@@ -197,7 +199,7 @@ func NewCertificate(data []byte) (certificate Certificate, err error) {
|
||||
// ReadCertificate creates a Certificate from []byte and returns any ExcessBytes at the end of the input.
|
||||
// returns err if the certificate could not be read.
|
||||
func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, err error) {
|
||||
certificate, err = NewCertificate(data)
|
||||
certificate, err = readCertificate(data)
|
||||
if err != nil && err.Error() == "certificate parsing warning: certificate data is longer than specified by length" {
|
||||
log.Warn("Certificate data longer than specified length")
|
||||
err = nil
|
||||
@@ -208,3 +210,53 @@ func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, er
|
||||
}).Debug("Read certificate and extracted remainder")
|
||||
return
|
||||
}
|
||||
|
||||
// NewCertificate creates a new Certificate with default NULL type
|
||||
func NewCertificate() *Certificate {
|
||||
return &Certificate{
|
||||
kind: Integer([]byte{CERT_NULL}),
|
||||
len: Integer([]byte{0}),
|
||||
payload: make([]byte, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// NewCertificateWithType creates a new Certificate with specified type and payload
|
||||
func NewCertificateWithType(certType uint8, payload []byte) (*Certificate, error) {
|
||||
// Validate certificate type
|
||||
switch certType {
|
||||
case CERT_NULL, CERT_HASHCASH, CERT_HIDDEN, CERT_SIGNED, CERT_MULTIPLE, CERT_KEY:
|
||||
// Valid type
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid certificate type: %d", certType)
|
||||
}
|
||||
|
||||
// For NULL certificates, payload should be empty
|
||||
if certType == CERT_NULL && len(payload) > 0 {
|
||||
return nil, errors.New("NULL certificates must have empty payload")
|
||||
}
|
||||
length, _ := NewIntegerFromInt(len(payload), 2)
|
||||
|
||||
cert := &Certificate{
|
||||
kind: Integer([]byte{certType}),
|
||||
len: *length,
|
||||
payload: make([]byte, len(payload)),
|
||||
}
|
||||
|
||||
// Copy payload if present
|
||||
if len(payload) > 0 {
|
||||
copy(cert.payload, payload)
|
||||
}
|
||||
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
func GetSignatureTypeFromCertificate(cert Certificate) (int, error) {
|
||||
if cert.Type() != CERT_KEY {
|
||||
return 0, fmt.Errorf("unexpected certificate type: %d", cert.Type)
|
||||
}
|
||||
if len(cert.payload) < 2 {
|
||||
return 0, fmt.Errorf("certificate payload too short to contain signature type")
|
||||
}
|
||||
sigType := int(binary.BigEndian.Uint16(cert.payload[0:2]))
|
||||
return sigType, nil
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ func TestCertificateTypeIsFirstByte(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
bytes := []byte{0x03, 0x00, 0x00}
|
||||
certificate, err := NewCertificate(bytes)
|
||||
certificate, err := readCertificate(bytes)
|
||||
cert_type := certificate.Type()
|
||||
|
||||
assert.Equal(cert_type, 3, "certificate.Type() should be the first bytes in a certificate")
|
||||
@@ -21,7 +21,7 @@ func TestCertificateLengthCorrect(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff}
|
||||
certificate, err := NewCertificate(bytes)
|
||||
certificate, err := readCertificate(bytes)
|
||||
cert_len := certificate.Length()
|
||||
|
||||
assert.Equal(cert_len, 2, "certificate.Length() should return integer from second two bytes")
|
||||
@@ -45,7 +45,7 @@ func TestCertificateLengthErrWhenDataTooShort(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
bytes := []byte{0x03, 0x00, 0x02, 0xff}
|
||||
certificate, err := NewCertificate(bytes)
|
||||
certificate, err := readCertificate(bytes)
|
||||
cert_len := certificate.Length()
|
||||
|
||||
assert.Equal(cert_len, 2, "certificate.Length() did not return indicated length when data was actually missing")
|
||||
@@ -58,7 +58,7 @@ func TestCertificateDataWhenCorrectSize(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
bytes := []byte{0x03, 0x00, 0x01, 0xaa}
|
||||
certificate, err := NewCertificate(bytes)
|
||||
certificate, err := readCertificate(bytes)
|
||||
cert_data := certificate.Data()
|
||||
|
||||
assert.Nil(err, "certificate.Data() returned error with valid data")
|
||||
@@ -85,7 +85,7 @@ func TestCertificateDataWhenTooShort(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
bytes := []byte{0x03, 0x00, 0x02, 0xff}
|
||||
certificate, err := NewCertificate(bytes)
|
||||
certificate, err := readCertificate(bytes)
|
||||
cert_data := certificate.Data()
|
||||
|
||||
if assert.NotNil(err) {
|
||||
|
@@ -134,6 +134,11 @@ func ToI2PString(data string) (str I2PString, err error) {
|
||||
// The remaining bytes after the specified length are also returned.
|
||||
// Returns a list of errors that occurred during parsing.
|
||||
func ReadI2PString(data []byte) (str I2PString, remainder []byte, err error) {
|
||||
if len(data) == 0 {
|
||||
err = errors.New("data slice is empty")
|
||||
log.WithError(err).Error("Passed data with len == 0")
|
||||
return
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(data),
|
||||
}).Debug("Reading I2PString from bytes")
|
||||
@@ -143,6 +148,11 @@ func ReadI2PString(data []byte) (str I2PString, remainder []byte, err error) {
|
||||
return
|
||||
}
|
||||
data_len := length.Int() + 1
|
||||
if data_len > len(data) {
|
||||
err = fmt.Errorf("I2PString length %d exceeds available data %d", data_len-1, len(data)-1)
|
||||
log.WithError(err).Error("Failed to read I2PString")
|
||||
return
|
||||
}
|
||||
str = data[:data_len]
|
||||
remainder = data[data_len:]
|
||||
l, err := str.Length()
|
||||
|
@@ -38,7 +38,8 @@ type Destination struct {
|
||||
func (destination Destination) Base32Address() (str string) {
|
||||
log.Debug("Generating Base32 address for Destination")
|
||||
|
||||
dest := destination.KeysAndCert.KeyCertificate.Bytes()
|
||||
cert := destination.KeysAndCert.Certificate()
|
||||
dest := cert.Bytes()
|
||||
hash := crypto.SHA256(dest)
|
||||
str = strings.Trim(base32.EncodeToString(hash[:]), "=")
|
||||
str = str + ".b32.i2p"
|
||||
@@ -54,7 +55,8 @@ func (destination Destination) Base32Address() (str string) {
|
||||
func (destination Destination) Base64() string {
|
||||
log.Debug("Generating Base64 address for Destination")
|
||||
|
||||
dest := destination.KeysAndCert.KeyCertificate.Bytes()
|
||||
cert := destination.KeysAndCert.Certificate()
|
||||
dest := cert.Bytes()
|
||||
base64Address := base64.EncodeToString(dest)
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -66,7 +66,7 @@ const (
|
||||
KEYCERT_MIN_SIZE = 7
|
||||
)
|
||||
|
||||
// SigningPublicKey sizes for Signing Key Types
|
||||
// signingPublicKey sizes for Signing Key Types
|
||||
const (
|
||||
KEYCERT_SIGN_DSA_SHA1_SIZE = 128
|
||||
KEYCERT_SIGN_P256_SIZE = 64
|
||||
@@ -79,7 +79,7 @@ const (
|
||||
KEYCERT_SIGN_ED25519PH_SIZE = 32
|
||||
)
|
||||
|
||||
// PublicKey sizes for Public Key Types
|
||||
// publicKey sizes for Public Key Types
|
||||
const (
|
||||
KEYCERT_CRYPTO_ELG_SIZE = 256
|
||||
KEYCERT_CRYPTO_P256_SIZE = 64
|
||||
@@ -106,34 +106,34 @@ func (key_certificate KeyCertificate) Data() ([]byte, error) {
|
||||
data := key_certificate.Certificate.RawBytes()
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
}).Debug("Retrieved raw data from KeyCertificate")
|
||||
}).Debug("Retrieved raw data from keyCertificate")
|
||||
return key_certificate.Certificate.RawBytes(), nil
|
||||
}
|
||||
|
||||
// SigningPublicKeyType returns the SigningPublicKey type as a Go integer.
|
||||
// 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")
|
||||
}).Debug("Retrieved signingPublicKey type")
|
||||
return key_certificate.spkType.Int()
|
||||
}
|
||||
|
||||
// PublicKeyType returns the PublicKey type as a Go integer.
|
||||
// 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")
|
||||
}).Debug("Retrieved publicKey type")
|
||||
return key_certificate.cpkType.Int()
|
||||
}
|
||||
|
||||
// ConstructPublicKey returns a PublicKey constructed using any excess data that may be stored in the KeyCertififcate.
|
||||
// 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")
|
||||
}).Debug("Constructing publicKey from keyCertificate")
|
||||
key_type := key_certificate.PublicKeyType()
|
||||
if err != nil {
|
||||
return
|
||||
@@ -141,7 +141,7 @@ func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_ke
|
||||
data_len := len(data)
|
||||
if data_len < key_certificate.CryptoSize() {
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(KeyCertificate) ConstructPublicKey",
|
||||
"at": "(keyCertificate) ConstructPublicKey",
|
||||
"data_len": data_len,
|
||||
"required_len": KEYCERT_PUBKEY_SIZE,
|
||||
"reason": "not enough data",
|
||||
@@ -174,15 +174,15 @@ func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_ke
|
||||
func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (signing_public_key crypto.SigningPublicKey, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(data),
|
||||
}).Debug("Constructing SigningPublicKey from KeyCertificate")
|
||||
signing_key_type := key_certificate.PublicKeyType()
|
||||
}).Debug("Constructing signingPublicKey from keyCertificate")
|
||||
signing_key_type := key_certificate.SigningPublicKeyType()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data_len := len(data)
|
||||
if data_len < key_certificate.SignatureSize() {
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(KeyCertificate) ConstructSigningPublicKey",
|
||||
"at": "(keyCertificate) ConstructSigningPublicKey",
|
||||
"data_len": data_len,
|
||||
"required_len": KEYCERT_SPK_SIZE,
|
||||
"reason": "not enough data",
|
||||
@@ -197,57 +197,60 @@ func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (si
|
||||
signing_public_key = dsa_key
|
||||
log.Debug("Constructed DSAPublicKey")
|
||||
case KEYCERT_SIGN_P256:
|
||||
var ec_key crypto.ECP256PublicKey
|
||||
copy(ec_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_P256_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = ec_key
|
||||
log.Debug("Constructed ECP256PublicKey")
|
||||
var ec_p256_key crypto.ECP256PublicKey
|
||||
copy(ec_p256_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_P256_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = ec_p256_key
|
||||
log.Debug("Constructed P256PublicKey")
|
||||
case KEYCERT_SIGN_P384:
|
||||
var ec_key crypto.ECP384PublicKey
|
||||
copy(ec_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_P384_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = ec_key
|
||||
log.Debug("Constructed ECP384PublicKey")
|
||||
var ec_p384_key crypto.ECP384PublicKey
|
||||
copy(ec_p384_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_P384_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = ec_p384_key
|
||||
log.Debug("Constructed P384PublicKey")
|
||||
case KEYCERT_SIGN_P521:
|
||||
var ec_key crypto.ECP521PublicKey
|
||||
extra := KEYCERT_SIGN_P521_SIZE - KEYCERT_SPK_SIZE
|
||||
copy(ec_key[:], data)
|
||||
copy(ec_key[KEYCERT_SPK_SIZE:], key_certificate.Certificate.RawBytes()[4:4+extra])
|
||||
signing_public_key = ec_key
|
||||
log.Debug("Constructed ECP521PublicKey")
|
||||
/*var ec_p521_key crypto.ECP521PublicKey
|
||||
copy(ec_p521_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_P521_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = ec_p521_key
|
||||
log.Debug("Constructed P521PublicKey")*/
|
||||
panic("unimplemented P521SigningPublicKey")
|
||||
case KEYCERT_SIGN_RSA2048:
|
||||
// var rsa_key crypto.RSA2048PublicKey
|
||||
// extra := KEYCERT_SIGN_RSA2048_SIZE - 128
|
||||
// copy(rsa_key[:], data)
|
||||
// copy(rsa_key[128:], key_certificate[4:4+extra])
|
||||
// signing_public_key = rsa_key
|
||||
log.WithFields(logrus.Fields{
|
||||
"signing_key_type": signing_key_type,
|
||||
}).Warn("Signing key type KEYCERT_SIGN_RSA2048 not implemented")
|
||||
/*var rsa2048_key crypto.RSA2048PublicKey
|
||||
copy(rsa2048_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_RSA2048_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = rsa2048_key
|
||||
log.Debug("Constructed RSA2048PublicKey")*/
|
||||
panic("unimplemented RSA2048SigningPublicKey")
|
||||
case KEYCERT_SIGN_RSA3072:
|
||||
log.WithFields(logrus.Fields{
|
||||
"signing_key_type": signing_key_type,
|
||||
}).Warn("Signing key type KEYCERT_SIGN_RSA3072 not implemented")
|
||||
/*var rsa3072_key crypto.RSA3072PublicKey
|
||||
copy(rsa3072_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_RSA3072_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = rsa3072_key
|
||||
log.Debug("Constructed RSA3072PublicKey")*/
|
||||
panic("unimplemented RSA3072SigningPublicKey")
|
||||
case KEYCERT_SIGN_RSA4096:
|
||||
log.WithFields(logrus.Fields{
|
||||
"signing_key_type": signing_key_type,
|
||||
}).Warn("Signing key type KEYCERT_SIGN_RSA4096 not implemented")
|
||||
/*var rsa4096_key crypto.RSA4096PublicKey
|
||||
copy(rsa4096_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_RSA4096_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = rsa4096_key
|
||||
log.Debug("Constructed RSA4096PublicKey")*/
|
||||
panic("unimplemented RSA4096SigningPublicKey")
|
||||
case KEYCERT_SIGN_ED25519:
|
||||
log.WithFields(logrus.Fields{
|
||||
"signing_key_type": signing_key_type,
|
||||
}).Warn("Signing key type KEYCERT_SIGN_ED25519 not implemented")
|
||||
var ed25519_key crypto.Ed25519PublicKey
|
||||
copy(ed25519_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_ED25519_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = ed25519_key
|
||||
log.Debug("Constructed Ed25519PublicKey")
|
||||
case KEYCERT_SIGN_ED25519PH:
|
||||
log.WithFields(logrus.Fields{
|
||||
"signing_key_type": signing_key_type,
|
||||
}).Warn("Signing key type KEYCERT_SIGN_ED25519PH not implemented")
|
||||
var ed25519ph_key crypto.Ed25519PublicKey
|
||||
copy(ed25519ph_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_ED25519PH_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = ed25519ph_key
|
||||
log.Debug("Constructed Ed25519PHPublicKey")
|
||||
default:
|
||||
log.WithFields(logrus.Fields{
|
||||
"signing_key_type": signing_key_type,
|
||||
}).Warn("Unknown signing key type")
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SignatureSize return the size of a Signature corresponding to the Key Certificate's SigningPublicKey type.
|
||||
// SignatureSize return the size of a Signature corresponding to the Key Certificate's signingPublicKey type.
|
||||
func (key_certificate KeyCertificate) SignatureSize() (size int) {
|
||||
sizes := map[int]int{
|
||||
KEYCERT_SIGN_DSA_SHA1: KEYCERT_SIGN_DSA_SHA1_SIZE,
|
||||
@@ -269,7 +272,7 @@ 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.
|
||||
// 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,
|
||||
@@ -293,7 +296,7 @@ func (key_certificate KeyCertificate) CryptoSize() (size int) {
|
||||
func NewKeyCertificate(bytes []byte) (key_certificate *KeyCertificate, remainder []byte, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(bytes),
|
||||
}).Debug("Creating new KeyCertificate")
|
||||
}).Debug("Creating new keyCertificate")
|
||||
|
||||
var certificate Certificate
|
||||
certificate, remainder, err = ReadCertificate(bytes)
|
||||
@@ -302,9 +305,9 @@ func NewKeyCertificate(bytes []byte) (key_certificate *KeyCertificate, remainder
|
||||
return
|
||||
}
|
||||
if len(bytes) < KEYCERT_MIN_SIZE {
|
||||
log.WithError(err).Error("keyCertificate data too short")
|
||||
err = errors.New("error parsing key certificate: not enough data")
|
||||
remainder = bytes[KEYCERT_MIN_SIZE:]
|
||||
log.WithError(err).Error("KeyCertificate data too short")
|
||||
}
|
||||
key_certificate = &KeyCertificate{
|
||||
Certificate: certificate,
|
||||
@@ -320,20 +323,20 @@ func NewKeyCertificate(bytes []byte) (key_certificate *KeyCertificate, remainder
|
||||
"spk_type": key_certificate.spkType.Int(),
|
||||
"cpk_type": key_certificate.cpkType.Int(),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully created new KeyCertificate")
|
||||
}).Debug("Successfully created new keyCertificate")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// KeyCertificateFromCertificate returns a *KeyCertificate from a *Certificate.
|
||||
func KeyCertificateFromCertificate(certificate Certificate) *KeyCertificate {
|
||||
log.Debug("Creating KeyCertificate from Certificate")
|
||||
log.Debug("Creating keyCertificate from Certificate")
|
||||
// k, _, _ := NewKeyCertificate(certificate.RawBytes())
|
||||
k, _, err := NewKeyCertificate(certificate.RawBytes())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create KeyCertificate from Certificate")
|
||||
log.WithError(err).Error("Failed to create keyCertificate from Certificate")
|
||||
} else {
|
||||
log.Debug("Successfully created KeyCertificate from Certificate")
|
||||
log.Debug("Successfully created keyCertificate from Certificate")
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ func TestPublicKeyTypeReturnsCorrectInteger(t *testing.T) {
|
||||
key_cert, _, err := NewKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03})
|
||||
pk_type := key_cert.PublicKeyType()
|
||||
|
||||
assert.Nil(err, "PublicKey() returned error with valid data")
|
||||
assert.Nil(err, "publicKey() returned error with valid data")
|
||||
assert.Equal(pk_type, KEYCERT_SIGN_P521, "PublicKeyType() did not return correct typec")
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ func TestConstructSigningPublicKeyWithDSASHA1(t *testing.T) {
|
||||
spk, err := key_cert.ConstructSigningPublicKey(data)
|
||||
|
||||
assert.Nil(err, "ConstructSigningPublicKey() with DSA SHA1 returned error with valid data")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_DSA_SHA1_SIZE, "ConstructSigningPublicKey() with DSA SHA1 returned incorrect SigningPublicKey length")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_DSA_SHA1_SIZE, "ConstructSigningPublicKey() with DSA SHA1 returned incorrect signingPublicKey length")
|
||||
}
|
||||
|
||||
func TestConstructSigningPublicKeyWithP256(t *testing.T) {
|
||||
@@ -105,7 +105,7 @@ func TestConstructSigningPublicKeyWithP256(t *testing.T) {
|
||||
spk, err := key_cert.ConstructSigningPublicKey(data)
|
||||
|
||||
assert.Nil(err, "ConstructSigningPublicKey() with P256 returned err on valid data")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_P256_SIZE, "ConstructSigningPublicKey() with P256 returned incorrect SigningPublicKey length")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_P256_SIZE, "ConstructSigningPublicKey() with P256 returned incorrect signingPublicKey length")
|
||||
}
|
||||
|
||||
func TestConstructSigningPublicKeyWithP384(t *testing.T) {
|
||||
@@ -116,7 +116,7 @@ func TestConstructSigningPublicKeyWithP384(t *testing.T) {
|
||||
spk, err := key_cert.ConstructSigningPublicKey(data)
|
||||
|
||||
assert.Nil(err, "ConstructSigningPublicKey() with P384 returned err on valid data")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_P384_SIZE, "ConstructSigningPublicKey() with P384 returned incorrect SigningPublicKey length")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_P384_SIZE, "ConstructSigningPublicKey() with P384 returned incorrect signingPublicKey length")
|
||||
}
|
||||
|
||||
func TestConstructSigningPublicKeyWithP521(t *testing.T) {
|
||||
@@ -127,5 +127,5 @@ func TestConstructSigningPublicKeyWithP521(t *testing.T) {
|
||||
spk, err := key_cert.ConstructSigningPublicKey(data)
|
||||
|
||||
assert.Nil(err, "ConstructSigningPublicKey() with P521 returned err on valid data")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_P521_SIZE, "ConstructSigningPublicKey() with P521 returned incorrect SigningPublicKey length")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_P521_SIZE, "ConstructSigningPublicKey() with P521 returned incorrect signingPublicKey length")
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
package keys_and_cert
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
@@ -30,7 +31,7 @@ Description
|
||||
An encryption public key, a signing public key, and a certificate, used as either a RouterIdentity or a Destination.
|
||||
|
||||
Contents
|
||||
A PublicKey followed by a SigningPublicKey and then a Certificate.
|
||||
A publicKey followed by a signingPublicKey and then a Certificate.
|
||||
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| public_key |
|
||||
@@ -55,14 +56,14 @@ A PublicKey followed by a SigningPublicKey and then a Certificate.
|
||||
| certificate |
|
||||
+----+----+----+-//
|
||||
|
||||
public_key :: PublicKey (partial or full)
|
||||
public_key :: publicKey (partial or full)
|
||||
length -> 256 bytes or as specified in key certificate
|
||||
|
||||
padding :: random data
|
||||
length -> 0 bytes or as specified in key certificate
|
||||
padding length + signing_key length == 128 bytes
|
||||
|
||||
signing__key :: SigningPublicKey (partial or full)
|
||||
signing__key :: signingPublicKey (partial or full)
|
||||
length -> 128 bytes or as specified in key certificate
|
||||
padding length + signing_key length == 128 bytes
|
||||
|
||||
@@ -76,34 +77,41 @@ total length: 387+ bytes
|
||||
//
|
||||
// https://geti2p.net/spec/common-structures#keysandcert
|
||||
type KeysAndCert struct {
|
||||
KeyCertificate *KeyCertificate
|
||||
keyCertificate *KeyCertificate
|
||||
publicKey crypto.PublicKey
|
||||
padding []byte
|
||||
Padding []byte
|
||||
signingPublicKey crypto.SigningPublicKey
|
||||
}
|
||||
|
||||
// Bytes returns the entire KeyCertificate in []byte form, trims payload to specified length.
|
||||
// Bytes returns the entire keyCertificate in []byte form, trims payload to specified length.
|
||||
func (keys_and_cert KeysAndCert) Bytes() []byte {
|
||||
bytes := keys_and_cert.KeyCertificate.Bytes()
|
||||
bytes := keys_and_cert.publicKey.Bytes()
|
||||
bytes = append(bytes, keys_and_cert.Padding...)
|
||||
bytes = append(bytes, keys_and_cert.signingPublicKey.Bytes()...)
|
||||
bytes = append(bytes, keys_and_cert.keyCertificate.Bytes()...)
|
||||
log.WithFields(logrus.Fields{
|
||||
"bytes_length": len(bytes),
|
||||
"bytes_length": len(bytes),
|
||||
"pk_bytes_length": len(keys_and_cert.publicKey.Bytes()),
|
||||
"padding_bytes_length": len(keys_and_cert.Padding),
|
||||
"spk_bytes_length": len(keys_and_cert.signingPublicKey.Bytes()),
|
||||
"cert_bytes_length": len(keys_and_cert.keyCertificate.Bytes()),
|
||||
}).Debug("Retrieved bytes from KeysAndCert")
|
||||
return bytes
|
||||
}
|
||||
|
||||
// PublicKey returns the public key as a crypto.PublicKey.
|
||||
// publicKey returns the public key as a crypto.publicKey.
|
||||
func (keys_and_cert *KeysAndCert) PublicKey() (key crypto.PublicKey) {
|
||||
return keys_and_cert.publicKey
|
||||
}
|
||||
|
||||
// SigningPublicKey returns the signing public key.
|
||||
// signingPublicKey returns the signing public key.
|
||||
func (keys_and_cert *KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey) {
|
||||
return keys_and_cert.signingPublicKey
|
||||
}
|
||||
|
||||
// Certfificate returns the certificate.
|
||||
func (keys_and_cert *KeysAndCert) Certificate() (cert Certificate) {
|
||||
return keys_and_cert.KeyCertificate.Certificate
|
||||
return keys_and_cert.keyCertificate.Certificate
|
||||
}
|
||||
|
||||
// ReadKeysAndCert creates a new *KeysAndCert from []byte using ReadKeysAndCert.
|
||||
@@ -123,7 +131,7 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
|
||||
"reason": "not enough data",
|
||||
}).Error("error parsing keys and cert")
|
||||
err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
|
||||
keys_and_cert.KeyCertificate, remainder, _ = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
|
||||
keys_and_cert.keyCertificate, remainder, _ = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
|
||||
return
|
||||
} else if data_len < KEYS_AND_CERT_DATA_SIZE {
|
||||
log.WithFields(logrus.Fields{
|
||||
@@ -135,33 +143,110 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
|
||||
err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
|
||||
return
|
||||
}
|
||||
keys_and_cert.KeyCertificate, remainder, err = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
|
||||
keys_and_cert.keyCertificate, remainder, err = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create KeyCertificate")
|
||||
log.WithError(err).Error("Failed to create keyCertificate")
|
||||
return
|
||||
}
|
||||
// TODO: this only supports one key type right now and it's the old key type, but the layout is the same.
|
||||
// a case-switch which sets the size of the SPK and the PK should be used to replace the referenced KEYS_AND_CERT_PUBKEY_SIZE
|
||||
// and KEYS_AND_CERT_SPK_SIZE constants in the future.
|
||||
keys_and_cert.publicKey, err = keys_and_cert.KeyCertificate.ConstructPublicKey(data[:keys_and_cert.KeyCertificate.CryptoSize()])
|
||||
keys_and_cert.publicKey, err = keys_and_cert.keyCertificate.ConstructPublicKey(data[:keys_and_cert.keyCertificate.CryptoSize()])
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to construct PublicKey")
|
||||
log.WithError(err).Error("Failed to construct publicKey")
|
||||
return
|
||||
}
|
||||
keys_and_cert.signingPublicKey, err = keys_and_cert.KeyCertificate.ConstructSigningPublicKey(data[KEYS_AND_CERT_DATA_SIZE-keys_and_cert.KeyCertificate.SignatureSize() : KEYS_AND_CERT_DATA_SIZE])
|
||||
keys_and_cert.signingPublicKey, err = keys_and_cert.keyCertificate.ConstructSigningPublicKey(data[KEYS_AND_CERT_DATA_SIZE-keys_and_cert.keyCertificate.SignatureSize() : KEYS_AND_CERT_DATA_SIZE])
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to construct SigningPublicKey")
|
||||
log.WithError(err).Error("Failed to construct signingPublicKey")
|
||||
return
|
||||
}
|
||||
padding := data[KEYS_AND_CERT_PUBKEY_SIZE : KEYS_AND_CERT_DATA_SIZE-KEYS_AND_CERT_SPK_SIZE]
|
||||
keys_and_cert.padding = padding
|
||||
keys_and_cert.Padding = padding
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"public_key_type": keys_and_cert.KeyCertificate.PublicKeyType(),
|
||||
"signing_public_key_type": keys_and_cert.KeyCertificate.SigningPublicKeyType(),
|
||||
"public_key_type": keys_and_cert.keyCertificate.PublicKeyType(),
|
||||
"signing_public_key_type": keys_and_cert.keyCertificate.SigningPublicKeyType(),
|
||||
"padding_length": len(padding),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully read KeysAndCert")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewKeysAndCert creates a new KeysAndCert instance with the provided parameters.
|
||||
// It validates the sizes of the provided keys and padding before assembling the struct.
|
||||
func NewKeysAndCert(
|
||||
keyCertificate *KeyCertificate,
|
||||
publicKey crypto.PublicKey,
|
||||
padding []byte,
|
||||
signingPublicKey crypto.SigningPublicKey,
|
||||
) (*KeysAndCert, error) {
|
||||
log.Debug("Creating new KeysAndCert with provided parameters")
|
||||
|
||||
// 1. Validate keyCertificate
|
||||
if keyCertificate == nil {
|
||||
log.Error("KeyCertificate is nil")
|
||||
return nil, errors.New("KeyCertificate cannot be nil")
|
||||
}
|
||||
|
||||
// 2. Validate publicKey size
|
||||
if publicKey.Len() != KEYS_AND_CERT_PUBKEY_SIZE {
|
||||
log.WithFields(logrus.Fields{
|
||||
"expected_size": KEYS_AND_CERT_PUBKEY_SIZE,
|
||||
"actual_size": publicKey.Len(),
|
||||
}).Error("Invalid publicKey size")
|
||||
return nil, errors.New("publicKey has an invalid size")
|
||||
}
|
||||
|
||||
/*
|
||||
// 3. Validate signingPublicKey size
|
||||
if signingPublicKey.Len() != KEYS_AND_CERT_SPK_SIZE {
|
||||
log.WithFields(logrus.Fields{
|
||||
"expected_size": KEYS_AND_CERT_SPK_SIZE,
|
||||
"actual_size": signingPublicKey.Len(),
|
||||
}).Error("Invalid signingPublicKey size")
|
||||
return nil, errors.New("signingPublicKey has an invalid size")
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
// 4. Validate padding size
|
||||
publicKeyLength := publicKey.Len()
|
||||
signingPublicKeyLength := signingPublicKey.Len()
|
||||
totalKeysSize := publicKeyLength + signingPublicKeyLength
|
||||
expectedPaddingSize := KEYS_AND_CERT_DATA_SIZE - totalKeysSize
|
||||
if len(padding) != expectedPaddingSize {
|
||||
log.WithFields(logrus.Fields{
|
||||
"expected_size": expectedPaddingSize,
|
||||
"actual_size": len(padding),
|
||||
}).Warn("Invalid padding size")
|
||||
// generate some random padding and continue
|
||||
padding = make([]byte, expectedPaddingSize)
|
||||
_, err := rand.Read(padding)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to generate random padding")
|
||||
return nil, err
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"expected_size": expectedPaddingSize,
|
||||
"actual_size": len(padding),
|
||||
}).Warn("Generated random padding")
|
||||
}
|
||||
|
||||
// 5. Assemble KeysAndCert
|
||||
keysAndCert := &KeysAndCert{
|
||||
keyCertificate: keyCertificate,
|
||||
publicKey: publicKey,
|
||||
Padding: padding,
|
||||
signingPublicKey: signingPublicKey,
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"public_key_length": publicKey.Len(),
|
||||
"signing_public_key_length": signingPublicKey.Len(),
|
||||
"padding_length": len(padding),
|
||||
}).Debug("Successfully created KeysAndCert")
|
||||
|
||||
return keysAndCert, nil
|
||||
}
|
||||
|
@@ -32,13 +32,13 @@ Accurate for version 0.9.49
|
||||
|
||||
Description
|
||||
Contains all of the currently authorized Leases for a particular Destination, the
|
||||
PublicKey to which garlic messages can be encrypted, and then the SigningPublicKey
|
||||
publicKey to which garlic messages can be encrypted, and then the signingPublicKey
|
||||
that can be used to revoke this particular version of the structure. The LeaseSet is one
|
||||
of the two structures stored in the network database (the other being RouterInfo), and
|
||||
is kered under the SHA256 of the contained Destination.
|
||||
|
||||
Contents
|
||||
Destination, followed by a PublicKey for encryption, then a SigningPublicKey which
|
||||
Destination, followed by a publicKey for encryption, then a signingPublicKey which
|
||||
can be used to revoke this version of the LeaseSet, then a 1 byte Integer specifying how
|
||||
many Lease structures are in the set, followed by the actual Lease structures and
|
||||
finally a Signature of the previous bytes signed by the Destination's SigningPrivateKey.
|
||||
@@ -100,10 +100,10 @@ finally a Signature of the previous bytes signed by the Destination's SigningPri
|
||||
destination :: Destination
|
||||
length -> >= 387 bytes
|
||||
|
||||
encryption_key :: PublicKey
|
||||
encryption_key :: publicKey
|
||||
length -> 256 bytes
|
||||
|
||||
signing_key :: SigningPublicKey
|
||||
signing_key :: signingPublicKey
|
||||
length -> 128 bytes or as specified in destination's key certificate
|
||||
|
||||
num :: Integer
|
||||
@@ -157,7 +157,7 @@ func (lease_set LeaseSet) PublicKey() (public_key crypto.ElgPublicKey, err error
|
||||
remainder_len := len(remainder)
|
||||
if remainder_len < LEASE_SET_PUBKEY_SIZE {
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(LeaseSet) PublicKey",
|
||||
"at": "(LeaseSet) publicKey",
|
||||
"data_len": remainder_len,
|
||||
"required_len": LEASE_SET_PUBKEY_SIZE,
|
||||
"reason": "not enough data",
|
||||
@@ -167,7 +167,7 @@ func (lease_set LeaseSet) PublicKey() (public_key crypto.ElgPublicKey, err error
|
||||
return
|
||||
}
|
||||
copy(public_key[:], remainder[:LEASE_SET_PUBKEY_SIZE])
|
||||
log.Debug("Successfully retrieved PublicKey from LeaseSet")
|
||||
log.Debug("Successfully retrieved publicKey from LeaseSet")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -200,11 +200,11 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK
|
||||
}
|
||||
if cert_len == 0 {
|
||||
// No Certificate is present, return the LEASE_SET_SPK_SIZE byte
|
||||
// SigningPublicKey space as legacy DSA SHA1 SigningPublicKey.
|
||||
// signingPublicKey space as legacy DSA SHA1 signingPublicKey.
|
||||
var dsa_pk crypto.DSAPublicKey
|
||||
copy(dsa_pk[:], lease_set[offset:offset+LEASE_SET_SPK_SIZE])
|
||||
signing_public_key = dsa_pk
|
||||
log.Debug("Retrieved legacy DSA SHA1 SigningPublicKey")
|
||||
log.Debug("Retrieved legacy DSA SHA1 signingPublicKey")
|
||||
} else {
|
||||
// A Certificate is present in this LeaseSet's Destination
|
||||
cert_type := cert.Type()
|
||||
@@ -216,17 +216,17 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK
|
||||
lease_set[offset : offset+LEASE_SET_SPK_SIZE],
|
||||
)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to construct SigningPublicKey from KeyCertificate")
|
||||
log.WithError(err).Error("Failed to construct signingPublicKey from keyCertificate")
|
||||
} else {
|
||||
log.Debug("Retrieved SigningPublicKey from KeyCertificate")
|
||||
log.Debug("Retrieved signingPublicKey from keyCertificate")
|
||||
}
|
||||
} else {
|
||||
// No Certificate is present, return the LEASE_SET_SPK_SIZE byte
|
||||
// SigningPublicKey space as legacy DSA SHA1 SigningPublicKey.
|
||||
// signingPublicKey space as legacy DSA SHA1 signingPublicKey.
|
||||
var dsa_pk crypto.DSAPublicKey
|
||||
copy(dsa_pk[:], lease_set[offset:offset+LEASE_SET_SPK_SIZE])
|
||||
signing_public_key = dsa_pk
|
||||
log.Debug("Retrieved legacy DSA SHA1 SigningPublicKey (Certificate present but not Key Certificate)")
|
||||
log.Debug("Retrieved legacy DSA SHA1 signingPublicKey (Certificate present but not Key Certificate)")
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -358,7 +358,7 @@ func (lease_set LeaseSet) Verify() error {
|
||||
//data := lease_set[:data_end]
|
||||
//spk, _ := lease_set.
|
||||
// Destination().
|
||||
// SigningPublicKey()
|
||||
// signingPublicKey()
|
||||
//verifier, err := spk.NewVerifier()
|
||||
//if err != nil {
|
||||
// return err
|
||||
|
@@ -61,7 +61,7 @@ func buildSignature(size int) []byte {
|
||||
|
||||
func buildFullLeaseSet(n int) LeaseSet {
|
||||
lease_set_data := make([]byte, 0)
|
||||
lease_set_data = append(lease_set_data, buildDestination().KeysAndCert.KeyCertificate.RawBytes()...)
|
||||
lease_set_data = append(lease_set_data, buildDestination().KeysAndCert.Bytes()...)
|
||||
lease_set_data = append(lease_set_data, buildPublicKey()...)
|
||||
lease_set_data = append(lease_set_data, buildSigningKey()...)
|
||||
lease_set_data = append(lease_set_data, byte(n))
|
||||
|
@@ -2,11 +2,13 @@
|
||||
package router_address
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -152,14 +154,7 @@ func (router_address RouterAddress) Bytes() []byte {
|
||||
bytes := make([]byte, 0)
|
||||
bytes = append(bytes, router_address.TransportCost.Bytes()...)
|
||||
bytes = append(bytes, router_address.ExpirationDate.Bytes()...)
|
||||
strData, err := router_address.TransportType.Data()
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Error("RouterAddress.Bytes: error getting transport_style bytes")
|
||||
} else {
|
||||
bytes = append(bytes, strData...)
|
||||
}
|
||||
bytes = append(bytes, router_address.TransportType...)
|
||||
bytes = append(bytes, router_address.TransportOptions.Data()...)
|
||||
log.WithField("bytes_length", len(bytes)).Debug("Converted RouterAddress to bytes")
|
||||
return bytes
|
||||
@@ -359,3 +354,57 @@ func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []b
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NewRouterAddress creates a new RouterAddress with the provided parameters.
|
||||
// Returns a pointer to RouterAddress.
|
||||
func NewRouterAddress(cost uint8, expiration time.Time, transportType string, options map[string]string) (*RouterAddress, error) {
|
||||
log.Debug("Creating new RouterAddress")
|
||||
|
||||
// Create TransportCost as an Integer (1 byte)
|
||||
transportCost, err := NewIntegerFromInt(int(cost), 1)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create TransportCost Integer")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create ExpirationDate as a Date
|
||||
millis := expiration.UnixNano() / int64(time.Millisecond)
|
||||
dateBytes := make([]byte, DATE_SIZE)
|
||||
binary.BigEndian.PutUint64(dateBytes, uint64(millis))
|
||||
expirationDate, _, err := NewDate(dateBytes)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create ExpirationDate")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create TransportType as an I2PString
|
||||
transportTypeStr, err := ToI2PString(transportType)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create TransportType I2PString")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create TransportOptions as a Mapping
|
||||
transportOptions, err := GoMapToMapping(options)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create TransportOptions Mapping")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create RouterAddress
|
||||
ra := &RouterAddress{
|
||||
TransportCost: transportCost,
|
||||
ExpirationDate: expirationDate,
|
||||
TransportType: transportTypeStr,
|
||||
TransportOptions: transportOptions,
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"cost": cost,
|
||||
"expiration": expiration,
|
||||
"transportType": transportType,
|
||||
"options": options,
|
||||
}).Debug("Successfully created new RouterAddress")
|
||||
|
||||
return ra, nil
|
||||
}
|
||||
|
@@ -2,7 +2,10 @@
|
||||
package router_identity
|
||||
|
||||
import (
|
||||
"github.com/go-i2p/go-i2p/lib/common/certificate"
|
||||
"github.com/go-i2p/go-i2p/lib/common/key_certificate"
|
||||
. "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -47,3 +50,30 @@ func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder
|
||||
}).Debug("Successfully read RouterIdentity")
|
||||
return
|
||||
}
|
||||
|
||||
func NewRouterIdentity(publicKey crypto.PublicKey, signingPublicKey crypto.SigningPublicKey, cert certificate.Certificate, padding []byte) (*RouterIdentity, error) {
|
||||
log.Debug("Creating new RouterIdentity")
|
||||
|
||||
// Step 1: Create keyCertificate from the provided certificate.
|
||||
// Assuming NewKeyCertificate is a constructor that takes a Certificate and returns a keyCertificate.
|
||||
keyCert := key_certificate.KeyCertificateFromCertificate(cert)
|
||||
|
||||
// Step 2: Create KeysAndCert instance.
|
||||
keysAndCert, err := NewKeysAndCert(keyCert, publicKey, padding, signingPublicKey)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("NewKeysAndCert failed.")
|
||||
}
|
||||
|
||||
// Step 3: Initialize RouterIdentity with KeysAndCert.
|
||||
routerIdentity := RouterIdentity{
|
||||
KeysAndCert: *keysAndCert,
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"public_key_type": keyCert.PublicKeyType(),
|
||||
"signing_public_key_type": keyCert.SigningPublicKeyType(),
|
||||
"padding_length": len(padding),
|
||||
}).Debug("Successfully created RouterIdentity")
|
||||
|
||||
return &routerIdentity, nil
|
||||
}
|
||||
|
194
lib/common/router_info/10k_test.go
Normal file
194
lib/common/router_info/10k_test.go
Normal file
@@ -0,0 +1,194 @@
|
||||
package router_info
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func consolidateNetDb(sourcePath string, destPath string) error {
|
||||
// Create destination directory if it doesn't exist
|
||||
if err := os.MkdirAll(destPath, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create destination directory: %v", err)
|
||||
}
|
||||
|
||||
// Walk through all subdirectories
|
||||
return filepath.Walk(sourcePath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("error accessing path %q: %v", path, err)
|
||||
}
|
||||
|
||||
// Skip if it's a directory
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if this is a routerInfo file
|
||||
if strings.HasPrefix(info.Name(), "routerInfo-") && strings.HasSuffix(info.Name(), ".dat") {
|
||||
// Create source file path
|
||||
srcFile := path
|
||||
|
||||
// Create destination file path
|
||||
dstFile := filepath.Join(destPath, info.Name())
|
||||
|
||||
// Copy the file
|
||||
if err := copyFile(srcFile, dstFile); err != nil {
|
||||
return fmt.Errorf("failed to copy %s: %v", info.Name(), err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) error {
|
||||
sourceFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer sourceFile.Close()
|
||||
|
||||
destFile, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
_, err = io.Copy(destFile, sourceFile)
|
||||
return err
|
||||
}
|
||||
|
||||
func consolidateAllNetDbs(tempDir string) error {
|
||||
// Common paths for I2P and I2Pd netDb
|
||||
i2pPath := filepath.Join(os.Getenv("HOME"), ".i2p/netDb")
|
||||
i2pdPath := filepath.Join(os.Getenv("HOME"), ".i2pd/netDb")
|
||||
|
||||
// Create the temp directory
|
||||
if err := os.MkdirAll(tempDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create temp directory: %v", err)
|
||||
}
|
||||
|
||||
// Try to consolidate I2P netDb
|
||||
if _, err := os.Stat(i2pPath); err == nil {
|
||||
if err := consolidateNetDb(i2pPath, tempDir); err != nil {
|
||||
fmt.Printf("Warning: Error processing I2P netDb: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Try to consolidate I2Pd netDb
|
||||
if _, err := os.Stat(i2pdPath); err == nil {
|
||||
if err := consolidateNetDb(i2pdPath, tempDir); err != nil {
|
||||
fmt.Printf("Warning: Error processing I2Pd netDb: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func cleanupTempDir(path string) error {
|
||||
if err := os.RemoveAll(path); err != nil {
|
||||
return fmt.Errorf("failed to cleanup temporary directory %s: %v", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func createTempNetDbDir() (string, error) {
|
||||
// Get system's temp directory in a platform-independent way
|
||||
baseDir := os.TempDir()
|
||||
|
||||
// Create unique directory name with timestamp
|
||||
timestamp := time.Now().Unix()
|
||||
dirName := fmt.Sprintf("go-i2p-testfiles-%d", timestamp)
|
||||
|
||||
// Join paths in a platform-independent way
|
||||
tempDir := filepath.Join(baseDir, dirName)
|
||||
|
||||
// Create the directory with appropriate permissions
|
||||
err := os.MkdirAll(tempDir, 0755)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create temporary directory: %v", err)
|
||||
}
|
||||
|
||||
return tempDir, nil
|
||||
}
|
||||
func Test10K(t *testing.T) {
|
||||
i2pPath := filepath.Join(os.Getenv("HOME"), ".i2p/netDb")
|
||||
i2pdPath := filepath.Join(os.Getenv("HOME"), ".i2pd/netDb")
|
||||
|
||||
// Skip if neither directory exists
|
||||
if _, err := os.Stat(i2pPath); os.IsNotExist(err) {
|
||||
if _, err := os.Stat(i2pdPath); os.IsNotExist(err) {
|
||||
t.Skip("Neither .i2p nor .i2pd netDb directories exist, so we will skip.")
|
||||
}
|
||||
}
|
||||
|
||||
tempDir, err := createTempNetDbDir()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp directory: %v", err)
|
||||
}
|
||||
//defer cleanupTempDir(tempDir)
|
||||
|
||||
if err := consolidateAllNetDbs(tempDir); err != nil {
|
||||
t.Fatalf("Failed to consolidate netDbs: %v", err)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
targetDir, err := createTempNetDbDir()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Read and process all router info files
|
||||
files, err := os.ReadDir(tempDir)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read temp directory: %v", err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if !file.IsDir() && strings.HasPrefix(file.Name(), "routerInfo-") {
|
||||
// Read the router info file
|
||||
log.Println("RI LOAD: ", file.Name())
|
||||
data, err := os.ReadFile(filepath.Join(tempDir, file.Name()))
|
||||
if err != nil {
|
||||
t.Logf("Failed to read file %s: %v", file.Name(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse the router info
|
||||
//fmt.Printf("data: %s\n", string(data))
|
||||
routerInfo, _, err := ReadRouterInfo(data)
|
||||
if err != nil {
|
||||
t.Logf("Failed to parse router info from %s: %v", file.Name(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Write the router info to the target directory
|
||||
routerBytes, err := routerInfo.Bytes()
|
||||
if err != nil {
|
||||
t.Logf("Failed to serialize router info %s: %v", file.Name(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = os.WriteFile(filepath.Join(targetDir, file.Name()), routerBytes, 0644)
|
||||
if err != nil {
|
||||
t.Logf("Failed to write router info %s: %v", file.Name(), err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
// Cleanup both directories
|
||||
if err := cleanupTempDir(tempDir); err != nil {
|
||||
log.WithError(err).Error("Failed to cleanup temp directory")
|
||||
t.Errorf("Failed to cleanup temp directory: %v", err)
|
||||
} else {
|
||||
log.Debug("Successfully cleaned up temp directory")
|
||||
}
|
||||
|
||||
if err := cleanupTempDir(targetDir); err != nil {
|
||||
log.WithError(err).Error("Failed to cleanup target directory")
|
||||
t.Errorf("Failed to cleanup target directory: %v", err)
|
||||
} else {
|
||||
log.Debug("Successfully cleaned up target directory")
|
||||
}
|
||||
}
|
@@ -2,9 +2,14 @@
|
||||
package router_info
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"github.com/go-i2p/go-i2p/lib/common/certificate"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -120,7 +125,7 @@ type RouterInfo struct {
|
||||
// Bytes returns the RouterInfo as a []byte suitable for writing to a stream.
|
||||
func (router_info RouterInfo) Bytes() (bytes []byte, err error) {
|
||||
log.Debug("Converting RouterInfo to bytes")
|
||||
bytes = append(bytes, router_info.router_identity.KeysAndCert.Bytes()...)
|
||||
bytes = append(bytes, router_info.router_identity.Bytes()...)
|
||||
bytes = append(bytes, router_info.published.Bytes()...)
|
||||
bytes = append(bytes, router_info.size.Bytes()...)
|
||||
for _, router_address := range router_info.addresses {
|
||||
@@ -133,17 +138,30 @@ func (router_info RouterInfo) Bytes() (bytes []byte, err error) {
|
||||
return bytes, err
|
||||
}
|
||||
|
||||
// Convert a byte slice into a string like [1, 2, 3] -> "1, 2, 3"
|
||||
func bytesToString(bytes []byte) string {
|
||||
str := "["
|
||||
for i, b := range bytes {
|
||||
str += strconv.Itoa(int(b))
|
||||
if i < len(bytes)-1 {
|
||||
str += ", "
|
||||
}
|
||||
}
|
||||
str += "]"
|
||||
return str
|
||||
}
|
||||
|
||||
func (router_info RouterInfo) String() string {
|
||||
log.Debug("Converting RouterInfo to string")
|
||||
str := "Certificate: " + string(router_info.router_identity.KeysAndCert.Bytes())
|
||||
str += "Published: " + string(router_info.published.Bytes())
|
||||
str += "Addresses:" + string(router_info.size.Bytes())
|
||||
str := "Certificate: " + bytesToString(router_info.router_identity.Bytes()) + "\n"
|
||||
str += "Published: " + bytesToString(router_info.published.Bytes()) + "\n"
|
||||
str += "Addresses:" + bytesToString(router_info.size.Bytes()) + "\n"
|
||||
for index, router_address := range router_info.addresses {
|
||||
str += "Address " + strconv.Itoa(index) + ": " + router_address.String()
|
||||
str += "Address " + strconv.Itoa(index) + ": " + router_address.String() + "\n"
|
||||
}
|
||||
str += "Peer Size: " + string(router_info.peer_size.Bytes())
|
||||
str += "Options: " + string(router_info.options.Data())
|
||||
str += "Signature: " + string([]byte(*router_info.signature))
|
||||
str += "Peer Size: " + bytesToString(router_info.peer_size.Bytes()) + "\n"
|
||||
str += "Options: " + bytesToString(router_info.options.Data()) + "\n"
|
||||
str += "Signature: " + bytesToString([]byte(*router_info.signature)) + "\n"
|
||||
log.WithField("string_length", len(str)).Debug("Converted RouterInfo to string")
|
||||
return str
|
||||
}
|
||||
@@ -156,7 +174,9 @@ 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)
|
||||
log.WithField("hash", hash).Debug("Calculated IdentHash for RouterInfo")
|
||||
return HashData(data)
|
||||
@@ -216,7 +236,7 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
|
||||
"required_len": ROUTER_INFO_MIN_SIZE,
|
||||
"reason": "not enough data",
|
||||
}).Error("error parsing router info")
|
||||
err = errors.New("error parsing router info: not enough data")
|
||||
err = errors.New("error parsing router info: not enough data to read identity")
|
||||
return
|
||||
}
|
||||
info.published, remainder, err = NewDate(remainder)
|
||||
@@ -227,7 +247,7 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
|
||||
"required_len": DATE_SIZE,
|
||||
"reason": "not enough data",
|
||||
}).Error("error parsing router info")
|
||||
err = errors.New("error parsing router info: not enough data")
|
||||
err = errors.New("error parsing router info: not enough data to read publish date")
|
||||
}
|
||||
info.size, remainder, err = NewInteger(remainder, 1)
|
||||
if err != nil {
|
||||
@@ -248,7 +268,7 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
|
||||
//"required_len": ROUTER_ADDRESS_SIZE,
|
||||
"reason": "not enough data",
|
||||
}).Error("error parsing router address")
|
||||
err = errors.New("error parsing router info: not enough data")
|
||||
err = errors.New("error parsing router info: not enough data to read router addresses")
|
||||
}
|
||||
info.addresses = append(info.addresses, &address)
|
||||
}
|
||||
@@ -272,7 +292,11 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
|
||||
}
|
||||
err = errors.New("error parsing router info: " + estring)
|
||||
}
|
||||
info.signature, remainder, err = NewSignature(remainder)
|
||||
sigType, err := certificate.GetSignatureTypeFromCertificate(info.router_identity.Certificate())
|
||||
log.WithFields(logrus.Fields{
|
||||
"sigType": sigType,
|
||||
}).Debug("Got sigType")
|
||||
info.signature, remainder, err = NewSignature(remainder, sigType)
|
||||
if err != nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(RouterInfo) ReadRouterInfo",
|
||||
@@ -280,7 +304,7 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
|
||||
//"required_len": MAPPING_SIZE,
|
||||
"reason": "not enough data",
|
||||
}).Error("error parsing router info")
|
||||
err = errors.New("error parsing router info: not enough data")
|
||||
err = errors.New("error parsing router info: not enough data to read signature")
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
@@ -293,6 +317,119 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
|
||||
return
|
||||
}
|
||||
|
||||
// serializeWithoutSignature serializes the RouterInfo up to (but not including) the signature.
|
||||
func (ri *RouterInfo) serializeWithoutSignature() []byte {
|
||||
var bytes []byte
|
||||
// Serialize RouterIdentity
|
||||
bytes = append(bytes, ri.router_identity.Bytes()...)
|
||||
|
||||
// Serialize Published Date
|
||||
bytes = append(bytes, ri.published.Bytes()...)
|
||||
|
||||
// Serialize Size
|
||||
bytes = append(bytes, ri.size.Bytes()...)
|
||||
|
||||
// Serialize Addresses
|
||||
for _, addr := range ri.addresses {
|
||||
bytes = append(bytes, addr.Bytes()...)
|
||||
}
|
||||
|
||||
// Serialize PeerSize (always zero)
|
||||
bytes = append(bytes, ri.peer_size.Bytes()...)
|
||||
|
||||
// Serialize Options
|
||||
bytes = append(bytes, ri.options.Data()...)
|
||||
|
||||
return bytes
|
||||
}
|
||||
|
||||
func NewRouterInfo(
|
||||
routerIdentity *RouterIdentity,
|
||||
publishedTime time.Time,
|
||||
addresses []*RouterAddress,
|
||||
options map[string]string,
|
||||
signingPrivateKey crypto.SigningPrivateKey,
|
||||
sigType int,
|
||||
) (*RouterInfo, error) {
|
||||
log.Debug("Creating new RouterInfo")
|
||||
|
||||
// 1. Create Published Date
|
||||
millis := publishedTime.UnixNano() / int64(time.Millisecond)
|
||||
dateBytes := make([]byte, DATE_SIZE)
|
||||
binary.BigEndian.PutUint64(dateBytes, uint64(millis))
|
||||
publishedDate, _, err := ReadDate(dateBytes)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Published Date")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. Create Size Integer
|
||||
sizeInt, err := NewIntegerFromInt(len(addresses), 1)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Size Integer")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 3. Create PeerSize Integer (always 0)
|
||||
peerSizeInt, err := NewIntegerFromInt(0, 1)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create PeerSize Integer")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 4. Convert options map to Mapping
|
||||
mapping, err := GoMapToMapping(options)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to convert options map to Mapping")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 5. Assemble RouterInfo without signature
|
||||
routerInfo := &RouterInfo{
|
||||
router_identity: *routerIdentity,
|
||||
published: &publishedDate,
|
||||
size: sizeInt,
|
||||
addresses: addresses,
|
||||
peer_size: peerSizeInt,
|
||||
options: mapping,
|
||||
signature: nil, // To be set after signing
|
||||
}
|
||||
|
||||
// 6. Serialize RouterInfo without signature
|
||||
dataBytes := routerInfo.serializeWithoutSignature()
|
||||
|
||||
// 7. Compute signature over serialized data
|
||||
signer, err := signingPrivateKey.NewSigner()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new signer")
|
||||
return nil, err
|
||||
}
|
||||
signatureBytes, err := signer.Sign(dataBytes)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to sign")
|
||||
}
|
||||
|
||||
// 8. Create Signature struct from signatureBytes
|
||||
sig, _, err := ReadSignature(signatureBytes, sigType)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Signature from signature bytes")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 9. Attach signature to RouterInfo
|
||||
routerInfo.signature = &sig
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"router_identity": routerIdentity,
|
||||
"published": publishedDate,
|
||||
"address_count": len(addresses),
|
||||
"options": options,
|
||||
"signature": sig,
|
||||
}).Debug("Successfully created RouterInfo")
|
||||
|
||||
return routerInfo, nil
|
||||
}
|
||||
|
||||
func (router_info *RouterInfo) RouterCapabilities() string {
|
||||
log.Debug("Retrieving RouterCapabilities")
|
||||
str, err := ToI2PString("caps")
|
||||
|
112
lib/common/router_info/router_info2_test.go
Normal file
112
lib/common/router_info/router_info2_test.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package router_info
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"github.com/go-i2p/go-i2p/lib/common/signature"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"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/router_address"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_identity"
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
"golang.org/x/crypto/openpgp/elgamal"
|
||||
)
|
||||
|
||||
func TestCreateRouterInfo(t *testing.T) {
|
||||
// Generate signing key pair (Ed25519)
|
||||
var ed25519_privkey crypto.Ed25519PrivateKey
|
||||
_, err := (&ed25519_privkey).Generate()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate Ed25519 private key: %v\n", err)
|
||||
}
|
||||
ed25519_pubkey_raw, err := ed25519_privkey.Public()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to derive Ed25519 public key: %v\n", err)
|
||||
}
|
||||
ed25519_pubkey, ok := ed25519_pubkey_raw.(crypto.SigningPublicKey)
|
||||
if !ok {
|
||||
t.Fatalf("Failed to get SigningPublicKey from Ed25519 public key")
|
||||
}
|
||||
|
||||
// Generate encryption key pair (ElGamal)
|
||||
var elgamal_privkey elgamal.PrivateKey
|
||||
err = crypto.ElgamalGenerate(&elgamal_privkey, rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate ElGamal private key: %v\n", err)
|
||||
}
|
||||
|
||||
// Convert elgamal private key to crypto.ElgPrivateKey
|
||||
var elg_privkey crypto.ElgPrivateKey
|
||||
xBytes := elgamal_privkey.X.Bytes()
|
||||
if len(xBytes) > 256 {
|
||||
t.Fatalf("ElGamal private key X too large")
|
||||
}
|
||||
copy(elg_privkey[256-len(xBytes):], xBytes)
|
||||
|
||||
// Convert elgamal public key to crypto.ElgPublicKey
|
||||
var elg_pubkey crypto.ElgPublicKey
|
||||
yBytes := elgamal_privkey.PublicKey.Y.Bytes()
|
||||
if len(yBytes) > 256 {
|
||||
t.Fatalf("ElGamal public key Y too large")
|
||||
}
|
||||
copy(elg_pubkey[256-len(yBytes):], yBytes)
|
||||
|
||||
// Ensure that elg_pubkey implements crypto.PublicKey interface
|
||||
var _ crypto.PublicKey = elg_pubkey
|
||||
|
||||
// Create KeyCertificate specifying key types
|
||||
var payload bytes.Buffer
|
||||
|
||||
signingPublicKeyType, _ := data.NewIntegerFromInt(7, 2)
|
||||
cryptoPublicKeyType, _ := data.NewIntegerFromInt(0, 2)
|
||||
|
||||
err = binary.Write(&payload, binary.BigEndian, signingPublicKeyType)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write signing public key type to payload: %v\n", err)
|
||||
}
|
||||
|
||||
err = binary.Write(&payload, binary.BigEndian, cryptoPublicKeyType)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write crypto public key type to payload: %v\n", err)
|
||||
}
|
||||
|
||||
// Create KeyCertificate specifying key types
|
||||
cert, err := certificate.NewCertificateWithType(certificate.CERT_KEY, payload.Bytes())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create new certificate: %v\n", err)
|
||||
}
|
||||
|
||||
// Create RouterIdentity
|
||||
routerIdentity, err := router_identity.NewRouterIdentity(elg_pubkey, ed25519_pubkey, *cert, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create router identity: %v\n", err)
|
||||
}
|
||||
// create some dummy addresses
|
||||
options := map[string]string{}
|
||||
routerAddress, err := router_address.NewRouterAddress(3, <-time.After(1*time.Second), "NTCP2", options)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create router address: %v\n", err)
|
||||
}
|
||||
routerAddresses := []*router_address.RouterAddress{routerAddress}
|
||||
// create router info
|
||||
routerInfo, err := NewRouterInfo(routerIdentity, time.Now(), routerAddresses, nil, &ed25519_privkey, signature.SIGNATURE_TYPE_EDDSA_SHA512_ED25519)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create router info: %v\n", err)
|
||||
}
|
||||
|
||||
t.Run("Serialize and Deserialize RouterInfo", func(t *testing.T) {
|
||||
routerInfoBytes, err := routerInfo.Bytes()
|
||||
t.Log(len(routerInfoBytes), routerInfo.String(), routerInfoBytes)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write RouterInfo to bytes: %v\n", err)
|
||||
}
|
||||
_, _, err = ReadRouterInfo(routerInfoBytes)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read routerInfoBytes: %v\n", err)
|
||||
}
|
||||
})
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
package signature
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -22,6 +23,19 @@ const (
|
||||
RedDSA_SHA512_Ed25519_SIZE = 64
|
||||
)
|
||||
|
||||
const (
|
||||
SIGNATURE_TYPE_DSA_SHA1 = 0
|
||||
SIGNATURE_TYPE_ECDSA_SHA256_P256 = 1
|
||||
SIGNATURE_TYPE_ECDSA_SHA384_P384 = 2
|
||||
SIGNATURE_TYPE_ECDSA_SHA512_P521 = 3
|
||||
SIGNATURE_TYPE_RSA_SHA256_2048 = 4
|
||||
SIGNATURE_TYPE_RSA_SHA384_3072 = 5
|
||||
SIGNATURE_TYPE_RSA_SHA512_4096 = 6
|
||||
SIGNATURE_TYPE_EDDSA_SHA512_ED25519 = 7
|
||||
SIGNATURE_TYPE_EDDSA_SHA512_ED25519PH = 8
|
||||
SIGNATURE_TYPE_REDDSA_SHA512_ED25519 = 11
|
||||
)
|
||||
|
||||
/*
|
||||
[Signature]
|
||||
Accurate for version 0.9.49
|
||||
@@ -39,30 +53,51 @@ DSA_SHA1. As of release 0.9.12, other types may be supported, depending on conte
|
||||
// https://geti2p.net/spec/common-structures#signature
|
||||
type Signature []byte
|
||||
|
||||
// ReadSignature returns Signature from a []byte.
|
||||
// ReadSignature returns a Signature from a []byte.
|
||||
// The remaining bytes after the specified length are also returned.
|
||||
// Returns a list of errors that occurred during parsing.
|
||||
func ReadSignature(bytes []byte) (info Signature, remainder []byte, err error) {
|
||||
// TODO: stub
|
||||
log.Warn("ReadSignature is not implemented")
|
||||
// Returns an error if there is insufficient data to read the signature.
|
||||
//
|
||||
// Since the signature type and length are inferred from context (the type of key used),
|
||||
// and are not explicitly stated, this function assumes the default signature type (DSA_SHA1)
|
||||
// with a length of 40 bytes.
|
||||
//
|
||||
// If a different signature type is expected based on context, this function should be
|
||||
// modified accordingly to handle the correct signature length.
|
||||
func ReadSignature(data []byte, sigType int) (sig Signature, remainder []byte, err error) {
|
||||
var sigLength int
|
||||
switch sigType {
|
||||
case SIGNATURE_TYPE_DSA_SHA1:
|
||||
sigLength = DSA_SHA1_SIZE
|
||||
case SIGNATURE_TYPE_EDDSA_SHA512_ED25519:
|
||||
sigLength = EdDSA_SHA512_Ed25519_SIZE
|
||||
default:
|
||||
err = fmt.Errorf("unsupported signature type: %d", sigType)
|
||||
return
|
||||
}
|
||||
|
||||
if len(data) < sigLength {
|
||||
err = fmt.Errorf("insufficient data to read signature: need %d bytes, have %d", sigLength, len(data))
|
||||
log.WithError(err).Error("Failed to read Signature")
|
||||
return
|
||||
}
|
||||
sig = data[:sigLength]
|
||||
remainder = data[sigLength:]
|
||||
return
|
||||
}
|
||||
|
||||
// NewSignature creates a new *Signature from []byte using ReadSignature.
|
||||
// Returns a pointer to Signature unlike ReadSignature.
|
||||
func NewSignature(data []byte) (session_tag *Signature, remainder []byte, err error) {
|
||||
func NewSignature(data []byte, sigType int) (signature *Signature, remainder []byte, err error) {
|
||||
log.WithField("input_length", len(data)).Debug("Creating new Signature")
|
||||
// sessionTag, remainder, err := ReadSignature(data)
|
||||
sig, remainder, err := ReadSignature(data)
|
||||
sig, remainder, err := ReadSignature(data, sigType)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read Signature")
|
||||
return nil, remainder, err
|
||||
}
|
||||
session_tag = &sig
|
||||
signature = &sig
|
||||
log.WithFields(logrus.Fields{
|
||||
"signature_length": len(sig),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully created new Signature")
|
||||
|
||||
return
|
||||
}
|
||||
|
@@ -14,8 +14,10 @@ var (
|
||||
log = logger.GetGoI2PLogger()
|
||||
)
|
||||
|
||||
const GOI2P_BASE_DIR = ".go-i2p"
|
||||
|
||||
func InitConfig() {
|
||||
defaultConfigDir := filepath.Join(os.Getenv("HOME"), ".go-i2p")
|
||||
defaultConfigDir := filepath.Join(os.Getenv("HOME"), GOI2P_BASE_DIR)
|
||||
defaultConfigFile := filepath.Join(defaultConfigDir, "config.yaml")
|
||||
|
||||
if CfgFile != "" {
|
||||
|
@@ -26,11 +26,11 @@ func home() string {
|
||||
}
|
||||
|
||||
func defaultBase() string {
|
||||
return filepath.Join(home(), "go-i2p", "base")
|
||||
return filepath.Join(home(), GOI2P_BASE_DIR, "base")
|
||||
}
|
||||
|
||||
func defaultConfig() string {
|
||||
return filepath.Join(home(), "go-i2p", "config")
|
||||
return filepath.Join(home(), GOI2P_BASE_DIR, "config")
|
||||
}
|
||||
|
||||
// defaults for router
|
||||
|
@@ -95,6 +95,10 @@ type DSAVerifier struct {
|
||||
|
||||
type DSAPublicKey [128]byte
|
||||
|
||||
func (k DSAPublicKey) Bytes() []byte {
|
||||
return k[:]
|
||||
}
|
||||
|
||||
// create a new dsa verifier
|
||||
func (k DSAPublicKey) NewVerifier() (v Verifier, err error) {
|
||||
log.Debug("Creating new DSA verifier")
|
||||
|
@@ -73,6 +73,10 @@ func (k ECP256PublicKey) Len() int {
|
||||
return len(k)
|
||||
}
|
||||
|
||||
func (k ECP256PublicKey) Bytes() []byte {
|
||||
return k[:]
|
||||
}
|
||||
|
||||
func (k ECP256PublicKey) NewVerifier() (Verifier, error) {
|
||||
log.Debug("Creating new P256 ECDSA verifier")
|
||||
// return createECVerifier(elliptic.P256(), crypto.SHA256, k[:])
|
||||
@@ -88,6 +92,10 @@ type (
|
||||
ECP384PrivateKey [48]byte
|
||||
)
|
||||
|
||||
func (k ECP384PublicKey) Bytes() []byte {
|
||||
return k[:]
|
||||
}
|
||||
|
||||
func (k ECP384PublicKey) Len() int {
|
||||
return len(k)
|
||||
}
|
||||
@@ -107,6 +115,10 @@ type (
|
||||
ECP521PrivateKey [66]byte
|
||||
)
|
||||
|
||||
func (k ECP521PublicKey) Bytes() []byte {
|
||||
return k[:]
|
||||
}
|
||||
|
||||
func (k ECP521PublicKey) Len() int {
|
||||
return len(k)
|
||||
}
|
||||
|
@@ -12,7 +12,10 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var Ed25519EncryptTooBig = errors.New("failed to encrypt data, too big for Ed25519")
|
||||
var (
|
||||
Ed25519EncryptTooBig = errors.New("failed to encrypt data, too big for Ed25519")
|
||||
ErrInvalidPublicKeySize = errors.New("failed to verify: invalid ed25519 public key size")
|
||||
)
|
||||
|
||||
type Ed25519PublicKey []byte
|
||||
|
||||
@@ -31,6 +34,10 @@ func (k Ed25519PublicKey) Len() int {
|
||||
return len(k)
|
||||
}
|
||||
|
||||
func (k Ed25519PublicKey) Bytes() []byte {
|
||||
return k
|
||||
}
|
||||
|
||||
func createEd25519PublicKey(data []byte) (k *ed25519.PublicKey) {
|
||||
log.WithField("data_length", len(data)).Debug("Creating Ed25519 public key")
|
||||
if len(data) == 256 {
|
||||
@@ -44,22 +51,36 @@ func createEd25519PublicKey(data []byte) (k *ed25519.PublicKey) {
|
||||
return
|
||||
}
|
||||
|
||||
func createEd25519Encryption(pub *ed25519.PublicKey, rand io.Reader) (enc *Ed25519Encryption, err error) {
|
||||
/*kbytes := make([]byte, 256)
|
||||
k := new(big.Int)
|
||||
for err == nil {
|
||||
_, err = io.ReadFull(rand, kbytes)
|
||||
k = new(big.Int).SetBytes(kbytes)
|
||||
k = k.Mod(k, pub.P)
|
||||
if k.Sign() != 0 {
|
||||
break
|
||||
}
|
||||
// createEd25519Encryption initializes the Ed25519Encryption struct using the public key.
|
||||
func createEd25519Encryption(pub *ed25519.PublicKey, randReader io.Reader) (*Ed25519Encryption, error) {
|
||||
// Define p = 2^255 - 19
|
||||
p := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 255), big.NewInt(19))
|
||||
|
||||
// Validate public key length
|
||||
if len(*pub) != ed25519.PublicKeySize {
|
||||
log.WithField("pub_length", len(*pub)).Error("Invalid Ed25519 public key size")
|
||||
return nil, ErrInvalidPublicKeySize
|
||||
}
|
||||
if err == nil {
|
||||
enc = &Ed25519Encryption{}
|
||||
}*/
|
||||
log.Warn("createEd25519Encryption is not implemented")
|
||||
return
|
||||
|
||||
// Convert public key bytes to big.Int
|
||||
a := new(big.Int).SetBytes(*pub)
|
||||
|
||||
// Generate a random scalar b1 in [0, p)
|
||||
b1, err := rand.Int(randReader, p)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to generate b1 for Ed25519Encryption")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize Ed25519Encryption struct
|
||||
enc := &Ed25519Encryption{
|
||||
p: p,
|
||||
a: a,
|
||||
b1: b1,
|
||||
}
|
||||
|
||||
log.Debug("Ed25519Encryption created successfully")
|
||||
return enc, nil
|
||||
}
|
||||
|
||||
type Ed25519Encryption struct {
|
||||
@@ -109,13 +130,18 @@ func (ed25519 *Ed25519Encryption) EncryptPadding(data []byte, zeroPadding bool)
|
||||
func (elg Ed25519PublicKey) NewEncrypter() (enc Encrypter, err error) {
|
||||
log.Debug("Creating new Ed25519 encrypter")
|
||||
k := createEd25519PublicKey(elg[:])
|
||||
if k == nil {
|
||||
return nil, errors.New("invalid public key format")
|
||||
}
|
||||
|
||||
enc, err = createEd25519Encryption(k, rand.Reader)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Ed25519 encrypter")
|
||||
} else {
|
||||
log.Debug("Ed25519 encrypter created successfully")
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
|
||||
log.Debug("Ed25519 encrypter created successfully")
|
||||
return enc, nil
|
||||
}
|
||||
|
||||
func (v *Ed25519Verifier) VerifyHash(h, sig []byte) (err error) {
|
||||
@@ -158,6 +184,42 @@ func (v *Ed25519Verifier) Verify(data, sig []byte) (err error) {
|
||||
|
||||
type Ed25519PrivateKey ed25519.PrivateKey
|
||||
|
||||
func (k Ed25519PrivateKey) NewDecrypter() (Decrypter, error) {
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (k Ed25519PrivateKey) NewSigner() (Signer, error) {
|
||||
if len(k) != ed25519.PrivateKeySize {
|
||||
return nil, errors.New("invalid ed25519 private key size")
|
||||
}
|
||||
return &Ed25519Signer{k: k}, nil
|
||||
}
|
||||
|
||||
func (k Ed25519PrivateKey) Len() int {
|
||||
return len(k)
|
||||
}
|
||||
|
||||
func (k *Ed25519PrivateKey) Generate() (SigningPrivateKey, error) {
|
||||
// Generate a new Ed25519 key pair
|
||||
_, priv, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Assign the generated private key to the receiver
|
||||
*k = Ed25519PrivateKey(priv)
|
||||
return k, nil
|
||||
}
|
||||
|
||||
func (k Ed25519PrivateKey) Public() (SigningPublicKey, error) {
|
||||
if len(k) != ed25519.PrivateKeySize {
|
||||
return nil, errors.New("invalid ed25519 private key size")
|
||||
}
|
||||
// The public key is the first 32 bytes of the private key's seed
|
||||
pubKey := k[32:]
|
||||
return Ed25519PublicKey(pubKey), nil
|
||||
}
|
||||
|
||||
type Ed25519Signer struct {
|
||||
k []byte
|
||||
}
|
||||
|
@@ -237,6 +237,10 @@ func (elg ElgPublicKey) Len() int {
|
||||
return len(elg)
|
||||
}
|
||||
|
||||
func (elg ElgPublicKey) Bytes() []byte {
|
||||
return elg[:]
|
||||
}
|
||||
|
||||
func (elg ElgPublicKey) NewEncrypter() (enc Encrypter, err error) {
|
||||
log.Debug("Creating new ElGamal encrypter")
|
||||
k := createElgamalPublicKey(elg[:])
|
||||
|
@@ -5,12 +5,57 @@ type (
|
||||
RSA2048PrivateKey [512]byte
|
||||
)
|
||||
|
||||
// Bytes implements SigningPublicKey.
|
||||
func (r RSA2048PublicKey) Bytes() []byte {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// Len implements SigningPublicKey.
|
||||
func (r RSA2048PublicKey) Len() int {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// NewVerifier implements SigningPublicKey.
|
||||
func (r RSA2048PublicKey) NewVerifier() (Verifier, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
type (
|
||||
RSA3072PublicKey [384]byte
|
||||
RSA3072PrivateKey [786]byte
|
||||
)
|
||||
|
||||
// Bytes implements SigningPublicKey.
|
||||
func (r RSA3072PublicKey) Bytes() []byte {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// Len implements SigningPublicKey.
|
||||
func (r RSA3072PublicKey) Len() int {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// NewVerifier implements SigningPublicKey.
|
||||
func (r RSA3072PublicKey) NewVerifier() (Verifier, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
type (
|
||||
RSA4096PublicKey [512]byte
|
||||
RSA4096PrivateKey [1024]byte
|
||||
)
|
||||
|
||||
// Bytes implements SigningPublicKey.
|
||||
func (r RSA4096PublicKey) Bytes() []byte {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// Len implements SigningPublicKey.
|
||||
func (r RSA4096PublicKey) Len() int {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// NewVerifier implements SigningPublicKey.
|
||||
func (r RSA4096PublicKey) NewVerifier() (Verifier, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
@@ -26,10 +26,11 @@ type SigningPublicKey interface {
|
||||
NewVerifier() (Verifier, error)
|
||||
// get the size of this public key
|
||||
Len() int
|
||||
Bytes() []byte
|
||||
}
|
||||
|
||||
type PublicKey interface {
|
||||
Len() int
|
||||
Bytes() []byte
|
||||
NewEncrypter() (Encrypter, error)
|
||||
}
|
||||
|
||||
|
@@ -69,59 +69,55 @@ func (r Reseed) SingleReseed(uri string) ([]router_info.RouterInfo, error) {
|
||||
|
||||
if su3file.FileType == su3.ZIP {
|
||||
if su3file.ContentType == su3.RESEED {
|
||||
content, err := io.ReadAll(su3file.Content(""))
|
||||
if err == nil {
|
||||
content, err := io.ReadAll(su3file.Content(""))
|
||||
if err == nil {
|
||||
signature, err := io.ReadAll(su3file.Signature())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Println("warning: this doesn't validate the signature yet", signature)
|
||||
log.Warn("Doesn't validate the signature yet", logrus.Fields{"signature": signature})
|
||||
}
|
||||
zip := filepath.Join(config.RouterConfigProperties.NetDb.Path, "reseed.zip")
|
||||
err = os.WriteFile(zip, content, 0o644)
|
||||
signature, err := io.ReadAll(su3file.Signature())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to write reseed zip file")
|
||||
log.WithError(err).Error("Failed to read SU3 file signature")
|
||||
return nil, err
|
||||
}
|
||||
// content is a zip file, unzip it and get the files
|
||||
files, err := unzip.New().Extract(zip, config.RouterConfigProperties.NetDb.Path)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to extract reseed zip file")
|
||||
return nil, err
|
||||
}
|
||||
if len(files) <= 0 {
|
||||
log.Error("Reseed appears to have no content")
|
||||
return nil, fmt.Errorf("error: reseed appears to have no content")
|
||||
}
|
||||
|
||||
log.WithField("file_count", len(files)).Debug("Successfully extracted reseed files")
|
||||
|
||||
var ris []router_info.RouterInfo
|
||||
for _, f := range files {
|
||||
riB, err := os.ReadFile(f)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("file", f).Warn("Failed to read router info file")
|
||||
continue
|
||||
}
|
||||
ri, _, err := router_info.ReadRouterInfo(riB)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("file", f).Warn("Failed to parse router info")
|
||||
continue
|
||||
}
|
||||
ris = append(ris, ri)
|
||||
}
|
||||
err = os.Remove(zip)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("Failed to remove reseed zip file")
|
||||
}
|
||||
log.WithField("router_info_count", len(ris)).Debug("Successfully processed reseed data")
|
||||
return ris, err
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to read SU3 file signature")
|
||||
log.Println("warning: this doesn't validate the signature yet", signature)
|
||||
log.Warn("Doesn't validate the signature yet", logrus.Fields{"signature": signature})
|
||||
}
|
||||
zip := filepath.Join(config.RouterConfigProperties.NetDb.Path, "reseed.zip")
|
||||
err = os.WriteFile(zip, content, 0o644)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to write reseed zip file")
|
||||
return nil, err
|
||||
}
|
||||
// content is a zip file, unzip it and get the files
|
||||
files, err := unzip.New().Extract(zip, config.RouterConfigProperties.NetDb.Path)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to extract reseed zip file")
|
||||
return nil, err
|
||||
}
|
||||
if len(files) <= 0 {
|
||||
log.Error("Reseed appears to have no content")
|
||||
return nil, fmt.Errorf("error: reseed appears to have no content")
|
||||
}
|
||||
|
||||
log.WithField("file_count", len(files)).Debug("Successfully extracted reseed files")
|
||||
|
||||
var ris []router_info.RouterInfo
|
||||
for _, f := range files {
|
||||
riB, err := os.ReadFile(f)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("file", f).Warn("Failed to read router info file")
|
||||
continue
|
||||
}
|
||||
ri, _, err := router_info.ReadRouterInfo(riB)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("file", f).Warn("Failed to parse router info")
|
||||
continue
|
||||
}
|
||||
ris = append(ris, ri)
|
||||
}
|
||||
err = os.Remove(zip)
|
||||
if err != nil {
|
||||
log.WithError(err).Warn("Failed to remove reseed zip file")
|
||||
}
|
||||
log.WithField("router_info_count", len(ris)).Debug("Successfully processed reseed data")
|
||||
return ris, err
|
||||
}
|
||||
}
|
||||
log.Error("Undefined reseed error")
|
||||
|
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@@ -103,7 +102,7 @@ func (db *StdNetDB) Size() (routers int) {
|
||||
log.WithError(err).Panic("Failed to recalculate NetDB size")
|
||||
}
|
||||
}
|
||||
data, err = ioutil.ReadFile(db.cacheFilePath())
|
||||
data, err = os.ReadFile(db.cacheFilePath())
|
||||
if err == nil {
|
||||
routers, err = strconv.Atoi(string(data))
|
||||
if err != nil {
|
||||
|
@@ -53,7 +53,7 @@ func fileRSAPubKey(t *testing.T, filename string) *rsa.PublicKey {
|
||||
}
|
||||
var pubKey *rsa.PublicKey
|
||||
if k, ok := cert.PublicKey.(*rsa.PublicKey); !ok {
|
||||
t.Fatalf("expected rsa.PublicKey from file %s", filename)
|
||||
t.Fatalf("expected rsa.publicKey from file %s", filename)
|
||||
} else {
|
||||
pubKey = k
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
"github.com/go-i2p/go-i2p/lib/transport/ntcp"
|
||||
"github.com/go-i2p/go-i2p/lib/transport/obfs"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -536,7 +536,7 @@ func TestEncryptDecryptPacketObfsOfflineWithFunc(t *testing.T) {
|
||||
}
|
||||
|
||||
// Obfuscate Alice's ephemeral public key in message 1
|
||||
obfuscatedMsg1, err := ntcp.ObfuscateEphemeralKey(msg1, aesKey)
|
||||
obfuscatedMsg1, err := obfs.ObfuscateEphemeralKey(msg1, aesKey)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to obfuscate message 1: %v", err)
|
||||
}
|
||||
@@ -546,7 +546,7 @@ func TestEncryptDecryptPacketObfsOfflineWithFunc(t *testing.T) {
|
||||
// -------------------------------
|
||||
|
||||
// Deobfuscate Alice's ephemeral public key in message 1
|
||||
deobfuscatedMsg1, err := ntcp.DeobfuscateEphemeralKey(obfuscatedMsg1, aesKey)
|
||||
deobfuscatedMsg1, err := obfs.DeobfuscateEphemeralKey(obfuscatedMsg1, aesKey)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to deobfuscate message 1: %v", err)
|
||||
}
|
||||
@@ -574,7 +574,7 @@ func TestEncryptDecryptPacketObfsOfflineWithFunc(t *testing.T) {
|
||||
}
|
||||
|
||||
// Obfuscate Bob's ephemeral public key in message 2
|
||||
obfuscatedMsg2, err := ntcp.ObfuscateEphemeralKey(msg2, aesKey)
|
||||
obfuscatedMsg2, err := obfs.ObfuscateEphemeralKey(msg2, aesKey)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to obfuscate message 2: %v", err)
|
||||
}
|
||||
@@ -584,7 +584,7 @@ func TestEncryptDecryptPacketObfsOfflineWithFunc(t *testing.T) {
|
||||
// -------------------------------
|
||||
|
||||
// Deobfuscate Bob's ephemeral public key in message 2
|
||||
deobfuscatedMsg2, err := ntcp.DeobfuscateEphemeralKey(obfuscatedMsg2, aesKey)
|
||||
deobfuscatedMsg2, err := obfs.DeobfuscateEphemeralKey(obfuscatedMsg2, aesKey)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to deobfuscate message 2: %v", err)
|
||||
}
|
||||
|
@@ -3,11 +3,79 @@ package noise
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
"github.com/flynn/noise"
|
||||
)
|
||||
|
||||
type HandshakeState struct {
|
||||
mutex sync.Mutex
|
||||
ephemeral *noise.DHKey
|
||||
pattern noise.HandshakePattern
|
||||
handshakeComplete bool
|
||||
HandKey noise.DHKey
|
||||
*noise.HandshakeState
|
||||
}
|
||||
|
||||
func NewHandshakeState(staticKey noise.DHKey, isInitiator bool) (*HandshakeState, error) {
|
||||
hs := &HandshakeState{
|
||||
pattern: noise.HandshakeXK,
|
||||
}
|
||||
|
||||
config := noise.Config{
|
||||
CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherAESGCM, noise.HashSHA256),
|
||||
Pattern: hs.pattern,
|
||||
Initiator: isInitiator,
|
||||
StaticKeypair: staticKey,
|
||||
}
|
||||
|
||||
protocol, err := noise.NewHandshakeState(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hs.HandshakeState = protocol
|
||||
return hs, nil
|
||||
}
|
||||
|
||||
// GenerateEphemeral creates the ephemeral keypair that will be used in handshake
|
||||
// This needs to be separate so NTCP2 can obfuscate it
|
||||
func (h *HandshakeState) GenerateEphemeral() (*noise.DHKey, error) {
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
|
||||
dhKey, err := noise.DH25519.GenerateKeypair(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h.ephemeral = &dhKey
|
||||
return &dhKey, nil
|
||||
}
|
||||
|
||||
// SetEphemeral allows setting a potentially modified ephemeral key
|
||||
// This is needed for NTCP2's obfuscation layer
|
||||
func (h *HandshakeState) SetEphemeral(key *noise.DHKey) error {
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
h.ephemeral = key
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HandshakeState) WriteMessage(payload []byte) ([]byte, *noise.CipherState, *noise.CipherState, error) {
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
|
||||
return h.HandshakeState.WriteMessage(nil, payload)
|
||||
}
|
||||
|
||||
func (h *HandshakeState) ReadMessage(message []byte) ([]byte, *noise.CipherState, *noise.CipherState, error) {
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
|
||||
return h.HandshakeState.ReadMessage(nil, message)
|
||||
}
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
func (c *NoiseTransport) Handshake(routerInfo router_info.RouterInfo) error {
|
||||
|
@@ -3,61 +3,13 @@ package noise
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func ComposeReceiverHandshakeMessage(s noise.DHKey, rs []byte, payload []byte, ePrivate []byte) (negData, msg []byte, state *noise.HandshakeState, err error) {
|
||||
log.Debug("Starting ComposeReceiverHandshakeMessage")
|
||||
|
||||
if len(rs) != 0 && len(rs) != noise.DH25519.DHLen() {
|
||||
log.WithField("rs_length", len(rs)).Error("Invalid remote static key length")
|
||||
return nil, nil, nil, errors.New("only 32 byte curve25519 public keys are supported")
|
||||
}
|
||||
negData = make([]byte, 6)
|
||||
copy(negData, initNegotiationData(nil))
|
||||
pattern := noise.HandshakeXK
|
||||
negData[5] = NOISE_PATTERN_XK
|
||||
log.WithField("pattern", "XK").Debug("Noise pattern set")
|
||||
var random io.Reader
|
||||
if len(ePrivate) == 0 {
|
||||
random = rand.Reader
|
||||
log.Debug("Using crypto/rand as random source")
|
||||
} else {
|
||||
random = bytes.NewBuffer(ePrivate)
|
||||
log.Debug("Using provided ePrivate as random source")
|
||||
}
|
||||
prologue := make([]byte, 2, uint16Size+len(negData))
|
||||
binary.BigEndian.PutUint16(prologue, uint16(len(negData)))
|
||||
prologue = append(prologue, negData...)
|
||||
log.WithField("prologue_length", len(prologue)).Debug("Prologue created")
|
||||
// prologue = append(initString, prologue...)
|
||||
state, err = noise.NewHandshakeState(noise.Config{
|
||||
StaticKeypair: s,
|
||||
Initiator: false,
|
||||
Pattern: pattern,
|
||||
CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256),
|
||||
PeerStatic: rs,
|
||||
Prologue: prologue,
|
||||
Random: random,
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new handshake state")
|
||||
return
|
||||
}
|
||||
log.WithField("message_length", len(msg)).Debug("Handshake message composed successfully")
|
||||
// log.Debug("Handshake state created successfully")
|
||||
padBuf := make([]byte, 2+len(payload))
|
||||
copy(padBuf[2:], payload)
|
||||
msg, _, _, err = state.WriteMessage(msg, padBuf)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *NoiseSession) RunIncomingHandshake() error {
|
||||
log.Debug("Starting incoming handshake")
|
||||
|
||||
@@ -66,6 +18,9 @@ func (c *NoiseSession) RunIncomingHandshake() error {
|
||||
log.WithError(err).Error("Failed to compose receiver handshake message")
|
||||
return err
|
||||
}
|
||||
c.HandshakeState = &HandshakeState{
|
||||
HandshakeState: state,
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"negData_length": len(negData),
|
||||
"msg_length": len(msg),
|
||||
@@ -86,3 +41,51 @@ func (c *NoiseSession) RunIncomingHandshake() error {
|
||||
log.Debug("Incoming handshake completed successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
func ComposeReceiverHandshakeMessage(s noise.DHKey, rs []byte, payload []byte, ePrivate []byte) (negData, msg []byte, state *noise.HandshakeState, err error) {
|
||||
log.Debug("Starting ComposeReceiverHandshakeMessage")
|
||||
|
||||
if len(rs) != 0 && len(rs) != noise.DH25519.DHLen() {
|
||||
log.WithField("rs_length", len(rs)).Error("Invalid remote static key length")
|
||||
return nil, nil, nil, errors.New("only 32 byte curve25519 public keys are supported")
|
||||
}
|
||||
|
||||
negData = make([]byte, 6)
|
||||
copy(negData, initNegotiationData(nil))
|
||||
pattern := noise.HandshakeXK
|
||||
negData[5] = NOISE_PATTERN_XK
|
||||
|
||||
var random io.Reader
|
||||
if len(ePrivate) == 0 {
|
||||
random = rand.Reader
|
||||
log.Debug("Using crypto/rand as random source")
|
||||
} else {
|
||||
random = bytes.NewBuffer(ePrivate)
|
||||
}
|
||||
|
||||
config := noise.Config{
|
||||
CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherAESGCM, noise.HashSHA256),
|
||||
Pattern: pattern,
|
||||
Initiator: false,
|
||||
StaticKeypair: s,
|
||||
Random: random,
|
||||
}
|
||||
|
||||
state, err = noise.NewHandshakeState(config)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Write message 2, expecting no CipherStates yet
|
||||
msg, cs0, cs1, err := state.WriteMessage(nil, payload)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Verify no CipherStates are returned yet
|
||||
if cs0 != nil || cs1 != nil {
|
||||
return nil, nil, nil, errors.New("unexpected cipher states in message 2")
|
||||
}
|
||||
|
||||
return negData, msg, state, nil
|
||||
}
|
||||
|
@@ -3,7 +3,6 @@ package noise
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
@@ -12,56 +11,6 @@ import (
|
||||
"github.com/flynn/noise"
|
||||
)
|
||||
|
||||
func ComposeInitiatorHandshakeMessage(s noise.DHKey, rs []byte, payload []byte, ePrivate []byte) (negData, msg []byte, state *noise.HandshakeState, err error) {
|
||||
log.Debug("Starting ComposeInitiatorHandshakeMessage")
|
||||
if len(rs) != 0 && len(rs) != noise.DH25519.DHLen() {
|
||||
log.WithField("rs_length", len(rs)).Error("Invalid remote static key length")
|
||||
return nil, nil, nil, errors.New("only 32 byte curve25519 public keys are supported")
|
||||
}
|
||||
negData = make([]byte, 6)
|
||||
copy(negData, initNegotiationData(nil))
|
||||
pattern := noise.HandshakeXK
|
||||
negData[5] = NOISE_PATTERN_XK
|
||||
log.WithField("pattern", "XK").Debug("Noise pattern set")
|
||||
var random io.Reader
|
||||
if len(ePrivate) == 0 {
|
||||
random = rand.Reader
|
||||
log.Debug("Using crypto/rand as random source")
|
||||
} else {
|
||||
random = bytes.NewBuffer(ePrivate)
|
||||
log.Debug("Using provided ePrivate as random source")
|
||||
}
|
||||
prologue := make([]byte, 2, uint16Size+len(negData))
|
||||
binary.BigEndian.PutUint16(prologue, uint16(len(negData)))
|
||||
prologue = append(prologue, negData...)
|
||||
log.WithField("prologue_length", len(prologue)).Debug("Prologue created")
|
||||
// prologue = append(initString, prologue...)
|
||||
state, err = noise.NewHandshakeState(noise.Config{
|
||||
StaticKeypair: s,
|
||||
Initiator: true,
|
||||
Pattern: pattern,
|
||||
CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256),
|
||||
PeerStatic: rs,
|
||||
Prologue: prologue,
|
||||
Random: random,
|
||||
})
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new handshake state")
|
||||
return
|
||||
}
|
||||
log.Debug("Handshake state created successfully")
|
||||
padBuf := make([]byte, 2+len(payload))
|
||||
copy(padBuf[2:], payload)
|
||||
msg, _, _, err = state.WriteMessage(msg, padBuf)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to write handshake message")
|
||||
return
|
||||
}
|
||||
log.WithField("message_length", len(msg)).Debug("Handshake message composed successfully")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *NoiseSession) RunOutgoingHandshake() error {
|
||||
log.Debug("Starting outgoing handshake")
|
||||
|
||||
@@ -74,6 +23,9 @@ func (c *NoiseSession) RunOutgoingHandshake() error {
|
||||
"negData_length": len(negData),
|
||||
"msg_length": len(msg),
|
||||
}).Debug("Initiator handshake message composed")
|
||||
c.HandshakeState = &HandshakeState{
|
||||
HandshakeState: state,
|
||||
}
|
||||
|
||||
if _, err = c.Write(negData); err != nil {
|
||||
log.WithError(err).Error("Failed to write negotiation data")
|
||||
@@ -92,3 +44,49 @@ func (c *NoiseSession) RunOutgoingHandshake() error {
|
||||
log.Debug("Outgoing handshake completed successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
func ComposeInitiatorHandshakeMessage(s noise.DHKey, rs []byte, payload []byte, ePrivate []byte) (negData, msg []byte, state *noise.HandshakeState, err error) {
|
||||
log.Debug("Starting ComposeInitiatorHandshakeMessage")
|
||||
|
||||
if len(rs) != 0 && len(rs) != noise.DH25519.DHLen() {
|
||||
return nil, nil, nil, errors.New("only 32 byte curve25519 public keys are supported")
|
||||
}
|
||||
|
||||
negData = make([]byte, 6)
|
||||
copy(negData, initNegotiationData(nil))
|
||||
pattern := noise.HandshakeXK
|
||||
negData[5] = NOISE_PATTERN_XK
|
||||
|
||||
var random io.Reader
|
||||
if len(ePrivate) == 0 {
|
||||
random = rand.Reader
|
||||
} else {
|
||||
random = bytes.NewBuffer(ePrivate)
|
||||
}
|
||||
|
||||
config := noise.Config{
|
||||
CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherAESGCM, noise.HashSHA256),
|
||||
Pattern: pattern,
|
||||
Initiator: true,
|
||||
StaticKeypair: s,
|
||||
Random: random,
|
||||
}
|
||||
|
||||
state, err = noise.NewHandshakeState(config)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Write message, expecting no CipherStates yet since this is message 1
|
||||
msg, cs0, cs1, err := state.WriteMessage(nil, payload)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
// Verify no CipherStates are returned yet
|
||||
if cs0 != nil || cs1 != nil {
|
||||
return nil, nil, nil, errors.New("unexpected cipher states in message 1")
|
||||
}
|
||||
|
||||
return negData, msg, state, nil
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
@@ -19,19 +18,14 @@ import (
|
||||
type NoiseSession struct {
|
||||
router_info.RouterInfo
|
||||
*noise.CipherState
|
||||
sync.Mutex
|
||||
*sync.Cond
|
||||
*NoiseTransport // The parent transport, which "Dialed" the connection to the peer whith whom we established the session
|
||||
RecvQueue *cb.Queue
|
||||
SendQueue *cb.Queue
|
||||
SendKey noise.DHKey
|
||||
RecvKey noise.DHKey
|
||||
HandKey noise.DHKey
|
||||
VerifyCallback VerifyCallbackFunc
|
||||
handshakeBuffer bytes.Buffer
|
||||
activeCall int32
|
||||
handshakeComplete bool
|
||||
Conn net.Conn
|
||||
*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
|
||||
}
|
||||
|
||||
// RemoteAddr implements net.Conn
|
||||
@@ -116,15 +110,6 @@ func NewNoiseTransportSession(ri router_info.RouterInfo) (transport.TransportSes
|
||||
log.WithError(err).Error("Failed to dial address")
|
||||
return nil, err
|
||||
}
|
||||
/*
|
||||
return &NoiseSession{
|
||||
SendQueue: cb.New(1024),
|
||||
RecvQueue: cb.New(1024),
|
||||
RouterInfo: ri,
|
||||
Conn: socket,
|
||||
}, nil
|
||||
|
||||
*/
|
||||
session := &NoiseSession{
|
||||
SendQueue: cb.New(1024),
|
||||
RecvQueue: cb.New(1024),
|
||||
|
@@ -13,7 +13,6 @@ import (
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
"github.com/go-i2p/go-i2p/lib/common/data"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_identity"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
@@ -23,7 +22,6 @@ import (
|
||||
type NoiseTransport struct {
|
||||
sync.Mutex
|
||||
router_identity.RouterIdentity
|
||||
*noise.CipherState
|
||||
Listener net.Listener
|
||||
peerConnections map[data.Hash]transport.TransportSession
|
||||
}
|
||||
|
@@ -1,5 +1,101 @@
|
||||
package ntcp
|
||||
|
||||
// Session implements TransportSession
|
||||
// An established transport session
|
||||
type Session struct{}
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
"github.com/go-i2p/go-i2p/lib/transport/noise"
|
||||
)
|
||||
|
||||
/*
|
||||
Summary of what needs to be done:
|
||||
NTCP and SSU2 are both transport protocols based on noise, with additional features designed to prevent p2p traffic from being blocked by firewalls.
|
||||
These modifications affect how the Noise handshake takes place, in particular:
|
||||
- Ephemeral keys are transmitted **obfuscated** by encrypting them with the peer's known static public key.
|
||||
these modifications are simple enough, but for our purposes we also want to be able to re-use as much code as possible.
|
||||
So, what we need to do is devise a means of adding these modifications to the existing NoiseSession implementation.
|
||||
We could do this in any number of ways, we could:
|
||||
1. Implement a custom struct that embeds a NoiseSession and overrides the Compose*HandshakeMessage functions
|
||||
2. Modify the NoiseSession handshake functions to allow passing an obfuscation and/or padding function as a parameter
|
||||
3. Modify the NoiseSession implementation to allow replacing the Compose*HandshakeMessage functions with custom ones
|
||||
4. Refactor the NoiseSession implementation to break Compose*HandshakeMessage out into a separate interface, and implement that interface in a custom struct
|
||||
Ideally, we're already set up to do #1, but we'll see how it goes.
|
||||
Now is the right time to make changes if we need to, go-i2p is the only consumer of go-i2p right now, we can make our lives as easy as we want to.
|
||||
*/
|
||||
|
||||
// NTCP2Session extends the base noise.NoiseSession with NTCP2-specific functionality
|
||||
type NTCP2Session struct {
|
||||
*noise.NoiseSession
|
||||
paddingStrategy PaddingStrategy
|
||||
}
|
||||
|
||||
// NewNTCP2Session creates a new NTCP2 session using the existing noise implementation
|
||||
func NewNTCP2Session(noiseConfig router_info.RouterInfo) (*NTCP2Session, error) {
|
||||
baseNoiseSession, err := noise.NewNoiseTransportSession(noiseConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &NTCP2Session{
|
||||
NoiseSession: baseNoiseSession.(*noise.NoiseSession),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type PaddingStrategy interface {
|
||||
AddPadding(message []byte) []byte
|
||||
RemovePadding(message []byte) []byte
|
||||
}
|
||||
|
||||
// PeerStaticKey is equal to the NTCP2 peer's static public key, found in their router info
|
||||
func (s *NTCP2Session) peerStaticKey() ([32]byte, error) {
|
||||
for _, addr := range s.RouterInfo.RouterAddresses() {
|
||||
transportStyle, err := addr.TransportStyle().Data()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if transportStyle == NTCP_PROTOCOL_NAME {
|
||||
return addr.StaticKey()
|
||||
}
|
||||
}
|
||||
return [32]byte{}, fmt.Errorf("Remote static key error")
|
||||
}
|
||||
|
||||
// ObfuscateEphemeral implements NTCP2's key obfuscation using AES-256-CBC
|
||||
func (s *NTCP2Session) ObfuscateEphemeral(key []byte) ([]byte, error) {
|
||||
static, err := s.peerStaticKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block, err := aes.NewCipher(static[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
obfuscated := make([]byte, len(key))
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(obfuscated, key)
|
||||
|
||||
return obfuscated, nil
|
||||
}
|
||||
|
||||
// DeobfuscateEphemeral reverses the key obfuscation
|
||||
func (s *NTCP2Session) DeobfuscateEphemeral(obfuscated []byte) ([]byte, error) {
|
||||
static, err := s.peerStaticKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block, err := aes.NewCipher(static[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key := make([]byte, len(obfuscated))
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(key, obfuscated)
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
@@ -4,11 +4,85 @@ package ntcp
|
||||
* https://geti2p.net/spec/ntcp2
|
||||
**/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
"github.com/go-i2p/go-i2p/lib/transport"
|
||||
"github.com/go-i2p/go-i2p/lib/transport/noise"
|
||||
)
|
||||
|
||||
const (
|
||||
NTCP_PROTOCOL_VERSION = 2
|
||||
NTCP_PROTOCOL_NAME = "NTCP2"
|
||||
NTCP_MESSAGE_MAX_SIZE = 65537
|
||||
)
|
||||
|
||||
// Transport is an ntcp transport implementing transport.Transport interface
|
||||
type Transport struct{}
|
||||
var exampleNTCPTransport transport.Transport = &Transport{}
|
||||
|
||||
// Transport is an ntcp2 transport implementing transport.Transport interface
|
||||
type Transport struct {
|
||||
*noise.NoiseTransport
|
||||
}
|
||||
|
||||
func (t *Transport) Name() string {
|
||||
return NTCP_PROTOCOL_NAME
|
||||
}
|
||||
|
||||
func (t *Transport) Compatible(routerInfo router_info.RouterInfo) bool {
|
||||
// Check if the router info contains NTCP2 address and capabilities
|
||||
addresses := routerInfo.RouterAddresses()
|
||||
for _, addr := range addresses {
|
||||
transportStyle, err := addr.TransportStyle().Data()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if transportStyle == NTCP_PROTOCOL_NAME {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *Transport) GetSession(routerInfo router_info.RouterInfo) (transport.TransportSession, error) {
|
||||
// Create new NTCP2 session
|
||||
session, err := NewNTCP2Session(routerInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Perform handshake
|
||||
if err := session.Handshake(routerInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (t *Transport) Accept() (net.Conn, error) {
|
||||
conn, err := t.NoiseTransport.Accept()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// check if remote router address contains a compatible transport
|
||||
// first get the RemoteAddr
|
||||
remoteAddr := conn.LocalAddr()
|
||||
// then check if it's a router address
|
||||
routerAddr, ok := remoteAddr.(*router_info.RouterInfo)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("remote address is not a router address")
|
||||
}
|
||||
// then check if it's compatible
|
||||
if !t.Compatible(*routerAddr) {
|
||||
return nil, fmt.Errorf("remote router address is not compatible with NTCP2")
|
||||
}
|
||||
// Wrap connection with NTCP2 session
|
||||
session, err := NewNTCP2Session(remoteAddr.(router_info.RouterInfo)) // nil for incoming connections
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package ntcp
|
||||
package obfs
|
||||
|
||||
import (
|
||||
"fmt"
|
@@ -1 +1,10 @@
|
||||
package ssu
|
||||
|
||||
/*
|
||||
Summary of what needs to be done:
|
||||
In addition to being a modified Noise protocol implementation,
|
||||
SSU2 also includes peer-testing features and QUIC-inspired features for resuming interrupted sessions.
|
||||
If we've done our jobs correctly when we get to this point, we will be implementing a net.Conn interface
|
||||
that can do the peer-testing and session management stuff, and we will **layer** it with our Noise protocol
|
||||
implementation and the SSU2 modifications.
|
||||
*/
|
||||
|
@@ -1 +1,17 @@
|
||||
package ssu
|
||||
|
||||
/*
|
||||
Summary of what needs to be done:
|
||||
NTCP and SSU2 are both transport protocols based on noise, with additional features designed to prevent p2p traffic from being blocked by firewalls.
|
||||
These modifications affect how the Noise handshake takes place, in particular:
|
||||
- Ephemeral keys are transmitted **obfuscated** by encrypting them with the peer's known static public key.
|
||||
these modifications are simple enough, but for our purposes we also want to be able to re-use as much code as possible.
|
||||
So, what we need to do is devise a means of adding these modifications to the existing NoiseSession implementation.
|
||||
We could do this in any number of ways, we could:
|
||||
1. Implement a custom struct that embeds a NoiseSession and overrides the Compose*HandshakeMessage functions
|
||||
2. Modify the NoiseSession handshake functions to allow passing an obfuscation and/or padding function as a parameter
|
||||
3. Modify the NoiseSession implementation to allow replacing the Compose*HandshakeMessage functions with custom ones
|
||||
4. Refactor the NoiseSession implementation to break Compose*HandshakeMessage out into a separate interface, and implement that interface in a custom struct
|
||||
Ideally, we're already set up to do #1, but we'll see how it goes.
|
||||
Now is the right time to make changes if we need to, go-i2p is the only consumer of go-i2p right now, we can make our lives as easy as we want to.
|
||||
*/
|
||||
|
@@ -22,6 +22,8 @@ type TransportSession interface {
|
||||
// close the session cleanly
|
||||
// returns any errors that happen while closing the session
|
||||
Close() error
|
||||
// create a handshake message for the session
|
||||
// CreateHandshakeMessage() (i2np.I2NPMessage, error)
|
||||
}
|
||||
|
||||
type Transport interface {
|
||||
|
@@ -121,9 +121,11 @@ func (rt *RouterTimestamper) TimestampNow() {
|
||||
go rt.runOnce()
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *RouterTimestamper) secureRandBool(probability float64) bool {
|
||||
return rand.Float64() < probability
|
||||
}
|
||||
|
||||
func (rt *RouterTimestamper) performTimeQuery() bool {
|
||||
rt.updateConfig()
|
||||
preferIPv6 := checkIPv6Connectivity()
|
||||
@@ -270,6 +272,7 @@ func (rt *RouterTimestamper) run() {
|
||||
func (rt *RouterTimestamper) runOnce() {
|
||||
rt.performTimeQuery()
|
||||
}
|
||||
|
||||
func (rt *RouterTimestamper) queryTime(servers []string, timeout time.Duration, preferIPv6 bool) bool {
|
||||
found := make([]time.Duration, rt.concurringServers)
|
||||
var expectedDelta time.Duration
|
||||
@@ -279,7 +282,7 @@ func (rt *RouterTimestamper) queryTime(servers []string, timeout time.Duration,
|
||||
server := servers[rand.Intn(len(servers))]
|
||||
options := ntp.QueryOptions{
|
||||
Timeout: timeout,
|
||||
//TTL: 5,
|
||||
// TTL: 5,
|
||||
}
|
||||
|
||||
if preferIPv6 {
|
||||
|
@@ -1,10 +1,11 @@
|
||||
package sntp
|
||||
|
||||
import (
|
||||
"github.com/beevik/ntp"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/beevik/ntp"
|
||||
)
|
||||
|
||||
type MockNTPClient struct {
|
||||
@@ -86,6 +87,7 @@ func TestTimestampNow(t *testing.T) {
|
||||
t.Error("Expected at least one time update, got none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimestampNowWithRealNTP(t *testing.T) {
|
||||
defaultClient := &DefaultNTPClient{}
|
||||
timestamper := NewRouterTimestamper(defaultClient)
|
||||
@@ -140,6 +142,7 @@ func TestTimestampNowWithRealNTP(t *testing.T) {
|
||||
t.Logf("NTP Servers: %v", timestamper.servers)
|
||||
t.Logf("Priority Servers: %v", timestamper.priorityServers)
|
||||
}
|
||||
|
||||
func TestWaitForInitialization(t *testing.T) {
|
||||
defaultClient := &DefaultNTPClient{}
|
||||
timestamper := NewRouterTimestamper(defaultClient)
|
||||
|
@@ -2,8 +2,9 @@ package sntp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/beevik/ntp"
|
||||
"time"
|
||||
|
||||
"github.com/beevik/ntp"
|
||||
)
|
||||
|
||||
func (rt *RouterTimestamper) validateResponse(response *ntp.Response) bool {
|
||||
|
@@ -1,9 +1,10 @@
|
||||
package sntp
|
||||
|
||||
import (
|
||||
"github.com/beevik/ntp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/beevik/ntp"
|
||||
)
|
||||
|
||||
func TestValidateResponse(t *testing.T) {
|
||||
|
Reference in New Issue
Block a user