mirror of
https://github.com/go-i2p/go-i2p.git
synced 2025-06-30 19:53:23 -04:00
29
Makefile
29
Makefile
@ -46,4 +46,31 @@ callvis:
|
||||
go-callvis -format svg -focus upgrade -group pkg,type -limit github.com/go-i2p/go-i2p github.com/go-i2p/go-i2p
|
||||
|
||||
godoc:
|
||||
find lib -type d -exec bash -c "ls {}/*.go && godocdown -o ./{}/doc.md ./{}" \;
|
||||
find lib -type d -exec bash -c "ls {}/*.go && godocdown -o ./{}/doc.md ./{}" \;
|
||||
|
||||
# Include test definitions
|
||||
-include doc/tests/*.mk
|
||||
|
||||
# Define the all-tests target that runs every test suite
|
||||
test-all: test-string-all \
|
||||
test-mapping-all \
|
||||
test-crypto-aes-all \
|
||||
test-crypto-dsa-all \
|
||||
test-crypto-ed25519-all \
|
||||
test-crypto-elg-all \
|
||||
test-crypto-hmac-all \
|
||||
test-i2np-header-all \
|
||||
test-i2np-build-request-all \
|
||||
test-key-cert-all \
|
||||
test-keys-cert-all \
|
||||
test-lease-set-all \
|
||||
test-noise-transport-all \
|
||||
test-router-address-all \
|
||||
test-router-info-all \
|
||||
test-su3-all \
|
||||
test-tunnel-all
|
||||
|
||||
#-include $(shell find doc/tests -type f -name '*.mk') #search for .mk files recursively
|
||||
|
||||
#test-base64-encode-decode-not-mangled:
|
||||
#go test -v ./lib/common/base64 -run TestEncodeDecodeNotMangled
|
20
README.md
20
README.md
@ -93,6 +93,26 @@ please keep up with these changes, as they will not be backward compatible and r
|
||||
- [X] Data Types
|
||||
- [X] Session Tag
|
||||
|
||||
## Verbosity ##
|
||||
Logging can be enabled and configured using the DEBUG_I2P environment variable. By default, logging is disabled.
|
||||
|
||||
There are three available log levels:
|
||||
|
||||
- Debug
|
||||
```shell
|
||||
export DEBUG_I2P=debug
|
||||
```
|
||||
- Warn
|
||||
```shell
|
||||
export DEBUG_I2P=warn
|
||||
```
|
||||
- Error
|
||||
```shell
|
||||
export DEBUG_I2P=error
|
||||
```
|
||||
|
||||
If I2P_DEBUG is set to an unrecognized variable, it will fall back to "debug".
|
||||
|
||||
## Contributing
|
||||
|
||||
See CONTRIBUTING.md for more information.
|
||||
|
17
doc/tests/aes.mk
Normal file
17
doc/tests/aes.mk
Normal file
@ -0,0 +1,17 @@
|
||||
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
|
||||
|
||||
test-crypto-aes-validation:
|
||||
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
|
||||
|
||||
.PHONY: test-crypto-aes-all \
|
||||
test-crypto-aes-core \
|
||||
test-crypto-aes-validation \
|
||||
test-crypto-aes-padding
|
4
doc/tests/base32.mk
Normal file
4
doc/tests/base32.mk
Normal file
@ -0,0 +1,4 @@
|
||||
test-base32-encode-decode-not-mangled:
|
||||
go test -v ./lib/common/base32 -run TestEncodeDecodeNotMangled
|
||||
|
||||
.PHONY: test-base32-encode-decode-not-mangled
|
4
doc/tests/base64.mk
Normal file
4
doc/tests/base64.mk
Normal file
@ -0,0 +1,4 @@
|
||||
test-base64-encode-decode-not-mangled:
|
||||
go test -v ./lib/common/base64 -run TestEncodeDecodeNotMangled
|
||||
|
||||
.PHONY: test-base64-encode-decode-not-mangled
|
24
doc/tests/build_request_record.mk
Normal file
24
doc/tests/build_request_record.mk
Normal file
@ -0,0 +1,24 @@
|
||||
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
|
||||
|
||||
test-build-request-ident:
|
||||
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
|
||||
|
||||
.PHONY: test-build-request-all \
|
||||
test-build-request-receive \
|
||||
test-build-request-ident \
|
||||
test-build-request-components
|
61
doc/tests/certificate.mk
Normal file
61
doc/tests/certificate.mk
Normal file
@ -0,0 +1,61 @@
|
||||
|
||||
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
|
||||
|
||||
test-cert-length:
|
||||
go test -v ./lib/common/certificate -run TestCertificateLength
|
||||
|
||||
test-cert-data:
|
||||
go test -v ./lib/common/certificate -run TestCertificateData
|
||||
|
||||
test-cert-read:
|
||||
go test -v ./lib/common/certificate -run TestReadCertificate
|
||||
|
||||
test-cert-length-correct:
|
||||
go test -v ./lib/common/certificate -run TestCertificateLengthCorrect
|
||||
|
||||
test-cert-length-too-short:
|
||||
go test -v ./lib/common/certificate -run TestCertificateLengthErrWhenTooShort
|
||||
|
||||
test-cert-length-data-short:
|
||||
go test -v ./lib/common/certificate -run TestCertificateLengthErrWhenDataTooShort
|
||||
|
||||
test-cert-data-correct:
|
||||
go test -v ./lib/common/certificate -run TestCertificateDataWhenCorrectSize
|
||||
|
||||
test-cert-data-too-long:
|
||||
go test -v ./lib/common/certificate -run TestCertificateDataWhenTooLong
|
||||
|
||||
test-cert-data-too-short:
|
||||
go test -v ./lib/common/certificate -run TestCertificateDataWhenTooShort
|
||||
|
||||
test-cert-read-correct:
|
||||
go test -v ./lib/common/certificate -run TestReadCertificateWithCorrectData
|
||||
|
||||
test-cert-read-short:
|
||||
go test -v ./lib/common/certificate -run TestReadCertificateWithDataTooShort
|
||||
|
||||
test-cert-read-remainder:
|
||||
go test -v ./lib/common/certificate -run TestReadCertificateWithRemainder
|
||||
|
||||
test-cert-read-invalid:
|
||||
go test -v ./lib/common/certificate -run TestReadCertificateWithInvalidLength
|
||||
|
||||
# Declare all targets as PHONY
|
||||
.PHONY: 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
|
2
doc/tests/date.mk
Normal file
2
doc/tests/date.mk
Normal file
@ -0,0 +1,2 @@
|
||||
test-date-time-from-milliseconds:
|
||||
go test -v ./lib/common/data -run TestTimeFromMilliseconds
|
20
doc/tests/dsa.mk
Normal file
20
doc/tests/dsa.mk
Normal file
@ -0,0 +1,20 @@
|
||||
test-crypto-dsa-all: test-crypto-dsa test-crypto-dsa-benchmarks
|
||||
|
||||
test-crypto-dsa:
|
||||
go test -v ./lib/crypto -run TestDSA
|
||||
|
||||
test-crypto-dsa-benchmarks:
|
||||
go test -v ./lib/crypto -bench=DSA -run=^$
|
||||
|
||||
# Individual benchmarks
|
||||
test-crypto-dsa-bench-generate:
|
||||
go test -v ./lib/crypto -bench=DSAGenerate -run=^$
|
||||
|
||||
test-crypto-dsa-bench-sign-verify:
|
||||
go test -v ./lib/crypto -bench=DSASignVerify -run=^$
|
||||
|
||||
.PHONY: test-crypto-dsa-all \
|
||||
test-crypto-dsa \
|
||||
test-crypto-dsa-benchmarks \
|
||||
test-crypto-dsa-bench-generate \
|
||||
test-crypto-dsa-bench-sign-verify
|
7
doc/tests/ed25519.mk
Normal file
7
doc/tests/ed25519.mk
Normal file
@ -0,0 +1,7 @@
|
||||
test-crypto-ed25519-all: test-crypto-ed25519
|
||||
|
||||
test-crypto-ed25519:
|
||||
go test -v ./lib/crypto -run TestEd25519
|
||||
|
||||
.PHONY: test-crypto-ed25519-all \
|
||||
test-crypto-ed25519
|
24
doc/tests/elg.mk
Normal file
24
doc/tests/elg.mk
Normal file
@ -0,0 +1,24 @@
|
||||
test-crypto-elg-all: test-crypto-elg test-crypto-elg-benchmarks
|
||||
|
||||
test-crypto-elg:
|
||||
go test -v ./lib/crypto -run TestElg
|
||||
|
||||
test-crypto-elg-benchmarks:
|
||||
go test -v ./lib/crypto -bench=Elg -run=^$
|
||||
|
||||
# Individual benchmarks
|
||||
test-crypto-elg-bench-generate:
|
||||
go test -v ./lib/crypto -bench=ElgGenerate -run=^$
|
||||
|
||||
test-crypto-elg-bench-encrypt:
|
||||
go test -v ./lib/crypto -bench=ElgEncrypt -run=^$
|
||||
|
||||
test-crypto-elg-bench-decrypt:
|
||||
go test -v ./lib/crypto -bench=ElgDecrypt -run=^$
|
||||
|
||||
.PHONY: test-crypto-elg-all \
|
||||
test-crypto-elg \
|
||||
test-crypto-elg-benchmarks \
|
||||
test-crypto-elg-bench-generate \
|
||||
test-crypto-elg-bench-encrypt \
|
||||
test-crypto-elg-bench-decrypt
|
30
doc/tests/header.mk
Normal file
30
doc/tests/header.mk
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
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
|
||||
|
||||
test-i2np-message:
|
||||
go test -v ./lib/i2np -run TestReadI2NPNTCPMessageID
|
||||
|
||||
test-i2np-expiration:
|
||||
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
|
||||
|
||||
test-i2np-data:
|
||||
go test -v ./lib/i2np -run TestReadI2NPNTCPData
|
||||
|
||||
test-i2np-regression:
|
||||
go test -v ./lib/i2np -run TestCrasherRegression123781
|
||||
|
||||
.PHONY: test-i2np-header-all \
|
||||
test-i2np-type \
|
||||
test-i2np-message \
|
||||
test-i2np-expiration \
|
||||
test-i2np-ntcp-components \
|
||||
test-i2np-data \
|
||||
test-i2np-regression
|
7
doc/tests/hmac.mk
Normal file
7
doc/tests/hmac.mk
Normal file
@ -0,0 +1,7 @@
|
||||
test-crypto-hmac-all: test-crypto-hmac
|
||||
|
||||
test-crypto-hmac:
|
||||
go test -v ./lib/crypto -run Test_I2PHMAC
|
||||
|
||||
.PHONY: test-crypto-hmac-all \
|
||||
test-crypto-hmac
|
15
doc/tests/integer.mk
Normal file
15
doc/tests/integer.mk
Normal file
@ -0,0 +1,15 @@
|
||||
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
|
||||
|
||||
test-integer-one-byte:
|
||||
go test -v ./lib/common/integer -run TestWorksWithOneByte
|
||||
|
||||
test-integer-zero:
|
||||
go test -v ./lib/common/integer -run TestIsZeroWithNoData
|
||||
|
||||
.PHONY: test-integer-all \
|
||||
test-integer-big-endian \
|
||||
test-integer-one-byte \
|
||||
test-integer-zero
|
23
doc/tests/key_certificate.mk
Normal file
23
doc/tests/key_certificate.mk
Normal file
@ -0,0 +1,23 @@
|
||||
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
|
||||
|
||||
test-key-cert-public:
|
||||
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
|
||||
|
||||
.PHONY: test-key-cert-all \
|
||||
test-key-cert-signing \
|
||||
test-key-cert-public \
|
||||
test-key-cert-construct
|
30
doc/tests/keys_and_cert.mk
Normal file
30
doc/tests/keys_and_cert.mk
Normal file
@ -0,0 +1,30 @@
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
.PHONY: test-keys-cert-all \
|
||||
test-keys-cert-certificate \
|
||||
test-keys-cert-public \
|
||||
test-keys-cert-signing \
|
||||
test-keys-cert-creation
|
22
doc/tests/lease_set.mk
Normal file
22
doc/tests/lease_set.mk
Normal file
@ -0,0 +1,22 @@
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
test-lease-set-expiration:
|
||||
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 \
|
||||
test-lease-set-leases \
|
||||
test-lease-set-expiration
|
28
doc/tests/mapping.mk
Normal file
28
doc/tests/mapping.mk
Normal file
@ -0,0 +1,28 @@
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
test-mapping-conversion:
|
||||
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
|
||||
|
||||
.PHONY: test-mapping-all \
|
||||
test-mapping-values \
|
||||
test-mapping-duplicates \
|
||||
test-mapping-conversion \
|
||||
test-mapping-utils
|
2
doc/tests/mapping_values.mk
Normal file
2
doc/tests/mapping_values.mk
Normal file
@ -0,0 +1,2 @@
|
||||
test-mapping-values-order:
|
||||
go test -v ./lib/common/data -run TestMappingOrderSortsValuesThenKeys
|
19
doc/tests/noise.mk
Normal file
19
doc/tests/noise.mk
Normal file
@ -0,0 +1,19 @@
|
||||
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
|
||||
|
||||
test-noise-transport-connection:
|
||||
go test -v ./lib/transport/noise -run TestTransport
|
||||
|
||||
test-noise-packet-obfuscation:
|
||||
go test -v ./lib/transport/noise -run TestEncryptDecryptPacketObfsOffline
|
||||
|
||||
test-noise-packet-obfuscation-func:
|
||||
go test -v ./lib/transport/noise -run TestEncryptDecryptPacketObfsOfflineWithFunc
|
||||
|
||||
.PHONY: test-noise-transport-all \
|
||||
test-noise-packet-encryption \
|
||||
test-noise-transport-connection \
|
||||
test-noise-packet-obfuscation \
|
||||
test-noise-packet-obfuscation-func
|
19
doc/tests/router_address.mk
Normal file
19
doc/tests/router_address.mk
Normal file
@ -0,0 +1,19 @@
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
test-router-address-fuzz:
|
||||
go test -v ./lib/common/router_address -run TestCorrectsFuzzCrasher1
|
||||
|
||||
.PHONY: test-router-address-all \
|
||||
test-router-address-validation \
|
||||
test-router-address-functionality \
|
||||
test-router-address-fuzz
|
26
doc/tests/router_info.mk
Normal file
26
doc/tests/router_info.mk
Normal file
@ -0,0 +1,26 @@
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
test-router-info-identity:
|
||||
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
|
||||
|
||||
.PHONY: test-router-info-all \
|
||||
test-router-info-published \
|
||||
test-router-info-addresses \
|
||||
test-router-info-identity \
|
||||
test-router-info-misc
|
27
doc/tests/string.mk
Normal file
27
doc/tests/string.mk
Normal file
@ -0,0 +1,27 @@
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
test-string-conversion:
|
||||
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
|
||||
|
||||
.PHONY: test-string-all \
|
||||
test-string-length \
|
||||
test-string-data \
|
||||
test-string-conversion \
|
||||
test-string-read
|
11
doc/tests/su3.mk
Normal file
11
doc/tests/su3.mk
Normal file
@ -0,0 +1,11 @@
|
||||
test-su3-all: test-su3-read test-su3-signature
|
||||
|
||||
test-su3-read:
|
||||
go test -v ./lib/su3 -run TestRead
|
||||
|
||||
test-su3-signature:
|
||||
go test -v ./lib/su3 -run TestReadSignatureFirst
|
||||
|
||||
.PHONY: test-su3-all \
|
||||
test-su3-read \
|
||||
test-su3-signature
|
22
doc/tests/tunnel.mk
Normal file
22
doc/tests/tunnel.mk
Normal file
@ -0,0 +1,22 @@
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
test-tunnel-message-fragments:
|
||||
go test -v ./lib/tunnel -run TestDeliveryInstructionsWithFragments
|
||||
|
||||
.PHONY: test-tunnel-all \
|
||||
test-tunnel-delivery-instructions \
|
||||
test-tunnel-message \
|
||||
test-tunnel-message-padding \
|
||||
test-tunnel-message-fragments
|
32
go.mod
32
go.mod
@ -1,21 +1,43 @@
|
||||
module github.com/go-i2p/go-i2p
|
||||
|
||||
go 1.22
|
||||
|
||||
toolchain go1.22.5
|
||||
go 1.23.1
|
||||
|
||||
require (
|
||||
github.com/emirpasic/gods v1.18.1
|
||||
github.com/beevik/ntp v1.4.3
|
||||
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/stretchr/testify v1.9.0
|
||||
go.step.sm/crypto v0.51.2
|
||||
golang.org/x/crypto v0.26.0
|
||||
go.step.sm/crypto v0.53.0
|
||||
golang.org/x/crypto v0.27.0
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
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/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
|
||||
|
67
go.sum
67
go.sum
@ -1,45 +1,100 @@
|
||||
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/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=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e h1:NMjWYVkgcQHGOy0/VxU0TU6smrcoxzj9hwDesx2sB0w=
|
||||
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/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
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/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/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/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=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
go.step.sm/crypto v0.51.2 h1:5EiCGIMg7IvQTGmJrwRosbXeprtT80OhoS/PJarg60o=
|
||||
go.step.sm/crypto v0.51.2/go.mod h1:QK7czLjN2k+uqVp5CHXxJbhc70kVRSP+0CQF3zsR5M0=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
go.step.sm/crypto v0.53.0 h1:+1as1ogzuCzx15/468M4mEC5juogI5a0Fzbsyh1CuYY=
|
||||
go.step.sm/crypto v0.53.0/go.mod h1:AqLU78RqNUHepLzyOWZuNN/2++Lu7dZENdO9UzWOGSk=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
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/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.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@ -5,11 +5,16 @@ package certificate
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
// log "github.com/sirupsen/logrus"
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
|
||||
. "github.com/go-i2p/go-i2p/lib/common/data"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
// Certificate Types
|
||||
const (
|
||||
CERT_NULL = iota
|
||||
@ -70,14 +75,22 @@ func (c *Certificate) RawBytes() []byte {
|
||||
bytes := c.kind.Bytes()
|
||||
bytes = append(bytes, c.len.Bytes()...)
|
||||
bytes = append(bytes, c.payload...)
|
||||
log.WithFields(logrus.Fields{
|
||||
"raw_bytes_length": len(bytes),
|
||||
}).Debug("Generated raw bytes for certificate")
|
||||
return bytes
|
||||
}
|
||||
|
||||
// ExcessBytes returns the excess bytes in a certificate found after the specified payload length.
|
||||
func (c *Certificate) ExcessBytes() []byte {
|
||||
if len(c.payload) >= c.len.Int() {
|
||||
return c.payload[c.len.Int():]
|
||||
excess := c.payload[c.len.Int():]
|
||||
log.WithFields(logrus.Fields{
|
||||
"excess_bytes_length": len(excess),
|
||||
}).Debug("Found excess bytes in certificate")
|
||||
return excess
|
||||
}
|
||||
log.Debug("No excess bytes found in certificate")
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -86,6 +99,9 @@ func (c *Certificate) Bytes() []byte {
|
||||
bytes := c.kind.Bytes()
|
||||
bytes = append(bytes, c.len.Bytes()...)
|
||||
bytes = append(bytes, c.Data()...)
|
||||
log.WithFields(logrus.Fields{
|
||||
"bytes_length": len(bytes),
|
||||
}).Debug("Generated bytes for certificate")
|
||||
return bytes
|
||||
}
|
||||
|
||||
@ -97,12 +113,18 @@ func (c *Certificate) length() (cert_len int) {
|
||||
// Type returns the Certificate type specified in the first byte of the Certificate,
|
||||
func (c *Certificate) Type() (cert_type int) {
|
||||
cert_type = c.kind.Int()
|
||||
log.WithFields(logrus.Fields{
|
||||
"cert_type": cert_type,
|
||||
}).Debug("Retrieved certificate type")
|
||||
return
|
||||
}
|
||||
|
||||
// Length returns the payload length of a Certificate.
|
||||
func (c *Certificate) Length() (length int) {
|
||||
length = c.len.Int()
|
||||
log.WithFields(logrus.Fields{
|
||||
"length": length,
|
||||
}).Debug("Retrieved certificate length")
|
||||
return
|
||||
}
|
||||
|
||||
@ -111,9 +133,13 @@ func (c *Certificate) Data() (data []byte) {
|
||||
lastElement := c.Length()
|
||||
if lastElement > len(c.payload) {
|
||||
data = c.payload
|
||||
log.Warn("Certificate payload shorter than specified length")
|
||||
} else {
|
||||
data = c.payload[0:lastElement]
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
}).Debug("Retrieved certificate data")
|
||||
return
|
||||
}
|
||||
|
||||
@ -125,7 +151,7 @@ func NewCertificate(data []byte) (certificate Certificate, err error) {
|
||||
case 0:
|
||||
certificate.kind = Integer([]byte{0})
|
||||
certificate.len = Integer([]byte{0})
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Certificate) NewCertificate",
|
||||
"certificate_bytes_length": len(data),
|
||||
"reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()),
|
||||
@ -135,7 +161,7 @@ func NewCertificate(data []byte) (certificate Certificate, err error) {
|
||||
case 1, 2:
|
||||
certificate.kind = Integer(data[0 : len(data)-1])
|
||||
certificate.len = Integer([]byte{0})
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Certificate) NewCertificate",
|
||||
"certificate_bytes_length": len(data),
|
||||
"reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()),
|
||||
@ -149,7 +175,7 @@ func NewCertificate(data []byte) (certificate Certificate, err error) {
|
||||
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(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Certificate) NewCertificate",
|
||||
"certificate_bytes_length": certificate.len.Int(),
|
||||
"certificate_payload_length": payleng,
|
||||
@ -160,6 +186,10 @@ func NewCertificate(data []byte) (certificate Certificate, err error) {
|
||||
}).Error("invalid certificate, shorter than specified by length")
|
||||
return
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"type": certificate.kind.Int(),
|
||||
"length": certificate.len.Int(),
|
||||
}).Debug("Successfully created new certificate")
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -169,8 +199,12 @@ func NewCertificate(data []byte) (certificate Certificate, err error) {
|
||||
func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, err error) {
|
||||
certificate, err = NewCertificate(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
|
||||
}
|
||||
remainder = certificate.ExcessBytes()
|
||||
log.WithFields(logrus.Fields{
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Read certificate and extracted remainder")
|
||||
return
|
||||
}
|
||||
|
@ -5,9 +5,12 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
// DATE_SIZE is the length in bytes of an I2P Date.
|
||||
const DATE_SIZE = 8
|
||||
|
||||
@ -51,7 +54,7 @@ func (date Date) Time() (date_time time.Time) {
|
||||
// Any data after DATE_SIZE is returned as a remainder.
|
||||
func ReadDate(data []byte) (date Date, remainder []byte, err error) {
|
||||
if len(data) < 8 {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"data": data,
|
||||
}).Error("ReadDate: data is too short")
|
||||
err = errors.New("ReadDate: data is too short")
|
||||
@ -59,6 +62,10 @@ func ReadDate(data []byte) (date Date, remainder []byte, err error) {
|
||||
}
|
||||
copy(date[:], data[:8])
|
||||
remainder = data[8:]
|
||||
log.WithFields(logrus.Fields{
|
||||
"date_value": date.Int(),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully read Date from data")
|
||||
return
|
||||
}
|
||||
|
||||
@ -66,6 +73,15 @@ func ReadDate(data []byte) (date Date, remainder []byte, err error) {
|
||||
// Returns a pointer to Date unlike ReadDate.
|
||||
func NewDate(data []byte) (date *Date, remainder []byte, err error) {
|
||||
objdate, remainder, err := ReadDate(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new Date")
|
||||
return nil, remainder, err
|
||||
}
|
||||
|
||||
date = &objdate
|
||||
log.WithFields(logrus.Fields{
|
||||
"date_value": date.Int(),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully created new Date")
|
||||
return
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTimeFromMiliseconds(t *testing.T) {
|
||||
func TestTimeFromMilliseconds(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
next_day := Date{0x00, 0x00, 0x00, 0x00, 0x05, 0x26, 0x5c, 0x00}
|
||||
|
@ -3,7 +3,7 @@ package data
|
||||
import (
|
||||
"errors"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
/*
|
||||
@ -48,8 +48,12 @@ type Mapping struct {
|
||||
// Values returns the values contained in a Mapping as MappingValues.
|
||||
func (mapping Mapping) Values() MappingValues {
|
||||
if mapping.vals == nil {
|
||||
log.Debug("Mapping values are nil, returning empty MappingValues")
|
||||
return MappingValues{}
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"values_count": len(*mapping.vals),
|
||||
}).Debug("Retrieved Mapping values")
|
||||
return *mapping.vals
|
||||
}
|
||||
|
||||
@ -74,30 +78,40 @@ func (mapping *Mapping) Data() []byte {
|
||||
|
||||
// HasDuplicateKeys returns true if two keys in a mapping are identical.
|
||||
func (mapping *Mapping) HasDuplicateKeys() bool {
|
||||
log.Debug("Checking for duplicate keys in Mapping")
|
||||
seen_values := make(map[string]bool)
|
||||
values := mapping.Values()
|
||||
for _, pair := range values {
|
||||
key, _ := pair[0].Data()
|
||||
if _, present := seen_values[key]; present {
|
||||
log.WithFields(logrus.Fields{
|
||||
"duplicate_key": key,
|
||||
}).Warn("Found duplicate key in Mapping")
|
||||
return true
|
||||
} else {
|
||||
seen_values[key] = true
|
||||
}
|
||||
}
|
||||
log.Debug("No duplicate keys found in Mapping")
|
||||
return false
|
||||
}
|
||||
|
||||
// GoMapToMapping converts a Go map of unformatted strings to *Mapping.
|
||||
func GoMapToMapping(gomap map[string]string) (mapping *Mapping, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_map_size": len(gomap),
|
||||
}).Debug("Converting Go map to Mapping")
|
||||
map_vals := MappingValues{}
|
||||
for k, v := range gomap {
|
||||
key_str, kerr := ToI2PString(k)
|
||||
if kerr != nil {
|
||||
log.WithError(kerr).Error("Failed to convert key to I2PString")
|
||||
err = kerr
|
||||
return
|
||||
}
|
||||
val_str, verr := ToI2PString(v)
|
||||
if verr != nil {
|
||||
log.WithError(verr).Error("Failed to convert value to I2PString")
|
||||
err = verr
|
||||
return
|
||||
}
|
||||
@ -107,27 +121,46 @@ func GoMapToMapping(gomap map[string]string) (mapping *Mapping, err error) {
|
||||
)
|
||||
}
|
||||
mapping = ValuesToMapping(map_vals)
|
||||
log.WithFields(logrus.Fields{
|
||||
"mapping_size": len(map_vals),
|
||||
}).Debug("Successfully converted Go map to Mapping")
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the string parsing error indicates that the Mapping
|
||||
// should no longer be parsed.
|
||||
func stopValueRead(err error) bool {
|
||||
return err.Error() == "error parsing string: zero length"
|
||||
result := err.Error() == "error parsing string: zero length"
|
||||
if result {
|
||||
log.WithError(err).Debug("Stopping value read due to zero length error")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Determine if the first byte in a slice of bytes is the provided byte.
|
||||
func beginsWith(bytes []byte, chr byte) bool {
|
||||
return len(bytes) != 0 &&
|
||||
bytes[0] == chr
|
||||
/*
|
||||
return len(bytes) != 0 &&
|
||||
bytes[0] == chr
|
||||
*/
|
||||
result := len(bytes) != 0 && bytes[0] == chr
|
||||
log.WithFields(logrus.Fields{
|
||||
"bytes_length": len(bytes),
|
||||
"expected_char": string(chr),
|
||||
"result": result,
|
||||
}).Debug("Checked if bytes begin with specific character")
|
||||
return result
|
||||
}
|
||||
|
||||
// ReadMapping returns Mapping from a []byte.
|
||||
// The remaining bytes after the specified length are also returned.
|
||||
// Returns a list of errors that occurred during parsing.
|
||||
func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(bytes),
|
||||
}).Debug("Reading Mapping from bytes")
|
||||
if len(bytes) < 3 {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "ReadMapping",
|
||||
"reason": "zero length",
|
||||
}).Warn("mapping format violation")
|
||||
@ -137,16 +170,18 @@ func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error)
|
||||
}
|
||||
size, remainder, e := NewInteger(bytes, 2)
|
||||
if e != nil {
|
||||
log.WithError(e).Error("Failed to read Mapping size")
|
||||
err = append(err, e)
|
||||
}
|
||||
if size.Int() == 0 {
|
||||
log.Warn("Mapping size is zero")
|
||||
return
|
||||
}
|
||||
mapping.size = size
|
||||
map_bytes := remainder[:mapping.size.Int()]
|
||||
remainder = remainder[mapping.size.Int():]
|
||||
if len(remainder) == 0 {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "ReadMapping",
|
||||
"reason": "zero length",
|
||||
}).Warn("mapping format violation")
|
||||
@ -161,20 +196,38 @@ func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error)
|
||||
err = append(err, mappingValueErrs...)
|
||||
mapping.vals = vals
|
||||
if len(mappingValueErrs) > 0 {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "ReadMapping",
|
||||
"reason": "error parsing mapping values",
|
||||
}).Warn("mapping format violation")
|
||||
e := errors.New("error parsing mapping values")
|
||||
err = append(err, e)
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"mapping_size": mapping.size.Int(),
|
||||
"values_count": len(*mapping.vals),
|
||||
"remainder_length": len(remainder),
|
||||
"error_count": len(err),
|
||||
}).Debug("Finished reading Mapping")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewMapping creates a new *Mapping from []byte using ReadMapping.
|
||||
// Returns a pointer to Mapping unlike ReadMapping.
|
||||
func NewMapping(bytes []byte) (values *Mapping, remainder []byte, err []error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(bytes),
|
||||
}).Debug("Creating new Mapping")
|
||||
|
||||
objvalues, remainder, err := ReadMapping(bytes)
|
||||
values = &objvalues
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"values_count": len(values.Values()),
|
||||
"remainder_length": len(remainder),
|
||||
"error_count": len(err),
|
||||
}).Debug("Finished creating new Mapping")
|
||||
return
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"sort"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// MappingValues represents the parsed key value pairs inside of an I2P Mapping.
|
||||
@ -12,12 +12,22 @@ type MappingValues [][2]I2PString
|
||||
|
||||
func (m MappingValues) Get(key I2PString) I2PString {
|
||||
keyBytes, _ := key.Data()
|
||||
log.WithFields(logrus.Fields{
|
||||
"key": string(keyBytes),
|
||||
}).Debug("Searching for key in MappingValues")
|
||||
for _, pair := range m {
|
||||
kb, _ := pair[0][0:].Data()
|
||||
if kb == keyBytes {
|
||||
return pair[1][1:]
|
||||
log.WithFields(logrus.Fields{
|
||||
"key": string(keyBytes),
|
||||
"value": string(pair[1][1:]),
|
||||
}).Debug("Found matching key in MappingValues")
|
||||
return pair[1]
|
||||
}
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"key": string(keyBytes),
|
||||
}).Debug("Key not found in MappingValues")
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -27,6 +37,9 @@ func ValuesToMapping(values MappingValues) *Mapping {
|
||||
// Default length to 2 * len
|
||||
// 1 byte for ;
|
||||
// 1 byte for =
|
||||
log.WithFields(logrus.Fields{
|
||||
"values_count": len(values),
|
||||
}).Debug("Converting MappingValues to Mapping")
|
||||
baseLength := 2 * len(values)
|
||||
for _, mappingVals := range values {
|
||||
for _, keyOrVal := range mappingVals {
|
||||
@ -34,6 +47,10 @@ func ValuesToMapping(values MappingValues) *Mapping {
|
||||
}
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"mapping_size": baseLength,
|
||||
}).Debug("Created Mapping from MappingValues")
|
||||
|
||||
mappingSize, _ := NewIntegerFromInt(baseLength, 2)
|
||||
return &Mapping{
|
||||
size: mappingSize,
|
||||
@ -61,8 +78,13 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
|
||||
// mapping := remainder
|
||||
// var remainder = mapping
|
||||
// var err error
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(remainder),
|
||||
"map_length": map_length.Int(),
|
||||
}).Debug("Reading MappingValues")
|
||||
|
||||
if remainder == nil || len(remainder) < 1 {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Mapping) Values",
|
||||
"reason": "data shorter than expected",
|
||||
}).Error("mapping contained no data")
|
||||
@ -73,7 +95,7 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
|
||||
int_map_length := map_length.Int()
|
||||
mapping_len := len(remainder)
|
||||
if mapping_len > int_map_length {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Mapping) Values",
|
||||
"mapping_bytes_length": mapping_len,
|
||||
"mapping_length_field": int_map_length,
|
||||
@ -81,7 +103,7 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
|
||||
}).Warn("mapping format warning")
|
||||
errs = append(errs, errors.New("warning parsing mapping: data exists beyond length of mapping"))
|
||||
} else if int_map_length > mapping_len {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Mapping) Values",
|
||||
"mapping_bytes_length": mapping_len,
|
||||
"mapping_length_field": int_map_length,
|
||||
@ -105,7 +127,7 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
|
||||
// One byte for ;
|
||||
if len(remainder) < 6 {
|
||||
// Not returning an error here as the issue is already flagged by mapping length being wrong.
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Mapping) Values",
|
||||
"reason": "mapping format violation",
|
||||
}).Warn("mapping format violation, too few bytes for a kv pair")
|
||||
@ -128,7 +150,7 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
|
||||
keyAsString := string(keyBytes)
|
||||
_, ok := encounteredKeysMap[keyAsString]
|
||||
if ok {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Mapping) Values",
|
||||
"reason": "duplicate key in mapping",
|
||||
"key": string(key_str),
|
||||
@ -142,7 +164,7 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
|
||||
}
|
||||
|
||||
if !beginsWith(remainder, 0x3d) {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Mapping) Values",
|
||||
"reason": "expected =",
|
||||
"value:": string(remainder),
|
||||
@ -168,7 +190,7 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
|
||||
// log.Printf("(MAPPING VALUES DEBUG) Remainder: %s\n", remainder)
|
||||
// log.Printf("(MAPPING VALUES DEBUG) String: value: %s", val_str)
|
||||
if !beginsWith(remainder, 0x3b) {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Mapping) Values",
|
||||
"reason": "expected ;",
|
||||
"value:": string(remainder),
|
||||
@ -189,5 +211,12 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
|
||||
encounteredKeysMap[keyAsString] = true
|
||||
}
|
||||
values = &map_values
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"values_count": len(map_values),
|
||||
"remainder_length": len(remainder_bytes),
|
||||
"error_count": len(errs),
|
||||
}).Debug("Finished reading MappingValues")
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// STRING_MAX_SIZE is the maximum number of bytes that can be stored in an I2P string
|
||||
@ -32,7 +32,7 @@ type I2PString []byte
|
||||
// Returns error if the specified does not match the actual length or the string is otherwise invalid.
|
||||
func (str I2PString) Length() (length int, err error) {
|
||||
if len(str) == 0 {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(I2PString) Length",
|
||||
"reason": "no data",
|
||||
}).Error("error parsing string")
|
||||
@ -41,6 +41,7 @@ func (str I2PString) Length() (length int, err error) {
|
||||
}
|
||||
l, _, err := NewInteger(str[:], 1)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Integer from I2PString")
|
||||
return l.Int(), err
|
||||
}
|
||||
length = l.Int()
|
||||
@ -53,6 +54,12 @@ func (str I2PString) Length() (length int, err error) {
|
||||
"data": string(str),
|
||||
"reason": "data less than specified by length",
|
||||
}).Error("string format warning")*/
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(I2PString) Length",
|
||||
"string_bytes_length": str_len,
|
||||
"string_length_field": length,
|
||||
"reason": "data less than specified by length",
|
||||
}).Warn("string format warning")
|
||||
err = errors.New("string parsing warning: string data is shorter than specified by length")
|
||||
}
|
||||
return
|
||||
@ -65,31 +72,42 @@ func (str I2PString) Data() (data string, err error) {
|
||||
if err != nil {
|
||||
switch err.Error() {
|
||||
case "error parsing string: zero length":
|
||||
log.WithError(err).Warn("Zero length I2PString")
|
||||
return
|
||||
case "string parsing warning: string data is shorter than specified by length":
|
||||
log.WithError(err).Warn("I2PString data shorter than specified length")
|
||||
if is, e := ToI2PString(string(str[:])); e != nil {
|
||||
log.WithError(e).Error("Failed to convert short I2PString")
|
||||
return "", e
|
||||
} else {
|
||||
return is.Data()
|
||||
}
|
||||
case "string parsing warning: string contains data beyond length":
|
||||
log.WithError(err).Warn("I2PString contains data beyond specified length")
|
||||
data = string(str[1:])
|
||||
return
|
||||
}
|
||||
}
|
||||
if length == 0 {
|
||||
log.Debug("I2PString is empty")
|
||||
return
|
||||
}
|
||||
data = string(str[1 : length+1])
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
}).Debug("Retrieved I2PString data")
|
||||
return
|
||||
}
|
||||
|
||||
// ToI2PString converts a Go string to an I2PString.
|
||||
// Returns error if the string exceeds STRING_MAX_SIZE.
|
||||
func ToI2PString(data string) (str I2PString, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(data),
|
||||
}).Debug("Converting string to I2PString")
|
||||
data_len := len(data)
|
||||
if data_len > STRING_MAX_SIZE {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "ToI2PI2PString",
|
||||
"string_len": data_len,
|
||||
"max_len": STRING_MAX_SIZE,
|
||||
@ -101,6 +119,9 @@ func ToI2PString(data string) (str I2PString, err error) {
|
||||
i2p_string := []byte{byte(data_len)}
|
||||
i2p_string = append(i2p_string, []byte(data)...)
|
||||
str = I2PString(i2p_string)
|
||||
log.WithFields(logrus.Fields{
|
||||
"i2pstring_length": len(str),
|
||||
}).Debug("Successfully converted string to I2PString")
|
||||
return
|
||||
}
|
||||
|
||||
@ -113,8 +134,12 @@ 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) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(data),
|
||||
}).Debug("Reading I2PString from bytes")
|
||||
length, _, err := NewInteger(data, 1)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read I2PString length")
|
||||
return
|
||||
}
|
||||
data_len := length.Int() + 1
|
||||
@ -123,8 +148,16 @@ func ReadI2PString(data []byte) (str I2PString, remainder []byte, err error) {
|
||||
l, err := str.Length()
|
||||
if l != data_len-1 {
|
||||
err = fmt.Errorf("error reading I2P string, length does not match data")
|
||||
log.WithFields(logrus.Fields{
|
||||
"expected_length": data_len - 1,
|
||||
"actual_length": l,
|
||||
}).Error("I2PString length mismatch")
|
||||
return
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"string_length": l,
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully read I2PString from bytes")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,9 @@ package destination
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
. "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/base32"
|
||||
@ -11,6 +14,8 @@ import (
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
/*
|
||||
[Destination]
|
||||
Accurate for version 0.9.49
|
||||
@ -31,26 +36,50 @@ type Destination struct {
|
||||
|
||||
// Base32Address returns the I2P base32 address for this Destination.
|
||||
func (destination Destination) Base32Address() (str string) {
|
||||
log.Debug("Generating Base32 address for Destination")
|
||||
|
||||
dest := destination.KeysAndCert.KeyCertificate.Bytes()
|
||||
hash := crypto.SHA256(dest)
|
||||
str = strings.Trim(base32.EncodeToString(hash[:]), "=")
|
||||
str = str + ".b32.i2p"
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"base32_address": str,
|
||||
}).Debug("Generated Base32 address for Destination")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Base64 returns the I2P base64 address for this Destination.
|
||||
func (destination Destination) Base64() string {
|
||||
log.Debug("Generating Base64 address for Destination")
|
||||
|
||||
dest := destination.KeysAndCert.KeyCertificate.Bytes()
|
||||
return base64.EncodeToString(dest)
|
||||
base64Address := base64.EncodeToString(dest)
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"base64_address_length": len(base64Address),
|
||||
}).Debug("Generated Base64 address for Destination")
|
||||
|
||||
return base64Address
|
||||
}
|
||||
|
||||
// ReadDestination returns Destination from a []byte.
|
||||
// The remaining bytes after the specified length are also returned.
|
||||
// Returns a list of errors that occurred during parsing.
|
||||
func ReadDestination(data []byte) (destination Destination, remainder []byte, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(data),
|
||||
}).Debug("Reading Destination from bytes")
|
||||
|
||||
keys_and_cert, remainder, err := ReadKeysAndCert(data)
|
||||
destination = Destination{
|
||||
keys_and_cert,
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully read Destination from bytes")
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -30,12 +30,16 @@ payload :: data
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
. "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/crypto"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
// Key Certificate Signing Key Types
|
||||
const (
|
||||
KEYCERT_SIGN_DSA_SHA1 = iota
|
||||
@ -99,29 +103,44 @@ type KeyCertificate struct {
|
||||
|
||||
// Data returns the raw []byte contained in the Certificate.
|
||||
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")
|
||||
return key_certificate.Certificate.RawBytes(), nil
|
||||
}
|
||||
|
||||
// SigningPublicKeyType returns the SigningPublicKey type as a Go integer.
|
||||
func (key_certificate KeyCertificate) SigningPublicKeyType() (signing_pubkey_type int) {
|
||||
signing_pubkey_type = key_certificate.spkType.Int()
|
||||
log.WithFields(logrus.Fields{
|
||||
"signing_pubkey_type": signing_pubkey_type,
|
||||
}).Debug("Retrieved SigningPublicKey type")
|
||||
return key_certificate.spkType.Int()
|
||||
}
|
||||
|
||||
// PublicKeyType returns the PublicKey type as a Go integer.
|
||||
func (key_certificate KeyCertificate) PublicKeyType() (pubkey_type int) {
|
||||
pubkey_type = key_certificate.cpkType.Int()
|
||||
log.WithFields(logrus.Fields{
|
||||
"pubkey_type": pubkey_type,
|
||||
}).Debug("Retrieved PublicKey type")
|
||||
return key_certificate.cpkType.Int()
|
||||
}
|
||||
|
||||
// ConstructPublicKey returns a PublicKey constructed using any excess data that may be stored in the KeyCertififcate.
|
||||
// Returns enr errors encountered while parsing.
|
||||
func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_key crypto.PublicKey, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(data),
|
||||
}).Debug("Constructing PublicKey from KeyCertificate")
|
||||
key_type := key_certificate.PublicKeyType()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data_len := len(data)
|
||||
if data_len < key_certificate.CryptoSize() {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(KeyCertificate) ConstructPublicKey",
|
||||
"data_len": data_len,
|
||||
"required_len": KEYCERT_PUBKEY_SIZE,
|
||||
@ -135,24 +154,34 @@ func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_ke
|
||||
var elg_key crypto.ElgPublicKey
|
||||
copy(elg_key[:], data[KEYCERT_PUBKEY_SIZE-KEYCERT_CRYPTO_ELG_SIZE:KEYCERT_PUBKEY_SIZE])
|
||||
public_key = elg_key
|
||||
log.Debug("Constructed ElgPublicKey")
|
||||
case KEYCERT_CRYPTO_X25519:
|
||||
var ed25519_key crypto.Ed25519PublicKey
|
||||
copy(ed25519_key[:], data[KEYCERT_PUBKEY_SIZE-KEYCERT_CRYPTO_ELG_SIZE:KEYCERT_PUBKEY_SIZE])
|
||||
public_key = ed25519_key
|
||||
log.Debug("Constructed Ed25519PublicKey")
|
||||
default:
|
||||
log.WithFields(logrus.Fields{
|
||||
"key_type": key_type,
|
||||
}).Warn("Unknown public key type")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ConstructSigningPublicKey returns a SingingPublicKey constructed using any excess data that may be stored in the KeyCertificate.
|
||||
// Returns any errors encountered while parsing.
|
||||
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()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data_len := len(data)
|
||||
if data_len < key_certificate.SignatureSize() {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(KeyCertificate) ConstructSigningPublicKey",
|
||||
"data_len": data_len,
|
||||
"required_len": KEYCERT_SPK_SIZE,
|
||||
@ -166,31 +195,55 @@ func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (si
|
||||
var dsa_key crypto.DSAPublicKey
|
||||
copy(dsa_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_DSA_SHA1_SIZE:KEYCERT_SPK_SIZE])
|
||||
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")
|
||||
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")
|
||||
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")
|
||||
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")
|
||||
case KEYCERT_SIGN_RSA3072:
|
||||
log.WithFields(logrus.Fields{
|
||||
"signing_key_type": signing_key_type,
|
||||
}).Warn("Signing key type KEYCERT_SIGN_RSA3072 not implemented")
|
||||
case KEYCERT_SIGN_RSA4096:
|
||||
log.WithFields(logrus.Fields{
|
||||
"signing_key_type": signing_key_type,
|
||||
}).Warn("Signing key type KEYCERT_SIGN_RSA4096 not implemented")
|
||||
case KEYCERT_SIGN_ED25519:
|
||||
log.WithFields(logrus.Fields{
|
||||
"signing_key_type": signing_key_type,
|
||||
}).Warn("Signing key type KEYCERT_SIGN_ED25519 not implemented")
|
||||
case KEYCERT_SIGN_ED25519PH:
|
||||
log.WithFields(logrus.Fields{
|
||||
"signing_key_type": signing_key_type,
|
||||
}).Warn("Signing key type KEYCERT_SIGN_ED25519PH not implemented")
|
||||
default:
|
||||
log.WithFields(logrus.Fields{
|
||||
"signing_key_type": signing_key_type,
|
||||
}).Warn("Unknown signing key type")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -208,6 +261,11 @@ func (key_certificate KeyCertificate) SignatureSize() (size int) {
|
||||
KEYCERT_SIGN_ED25519PH: KEYCERT_SIGN_ED25519PH_SIZE,
|
||||
}
|
||||
key_type := key_certificate.SigningPublicKeyType()
|
||||
size = sizes[int(key_type)]
|
||||
log.WithFields(logrus.Fields{
|
||||
"key_type": key_type,
|
||||
"signature_size": size,
|
||||
}).Debug("Retrieved signature size")
|
||||
return sizes[int(key_type)]
|
||||
}
|
||||
|
||||
@ -221,6 +279,11 @@ func (key_certificate KeyCertificate) CryptoSize() (size int) {
|
||||
KEYCERT_CRYPTO_X25519: KEYCERT_CRYPTO_X25519_SIZE,
|
||||
}
|
||||
key_type := key_certificate.PublicKeyType()
|
||||
size = sizes[int(key_type)]
|
||||
log.WithFields(logrus.Fields{
|
||||
"key_type": key_type,
|
||||
"crypto_size": size,
|
||||
}).Debug("Retrieved crypto size")
|
||||
return sizes[int(key_type)]
|
||||
}
|
||||
|
||||
@ -228,14 +291,20 @@ func (key_certificate KeyCertificate) CryptoSize() (size int) {
|
||||
// The remaining bytes after the specified length are also returned.
|
||||
// Returns a list of errors that occurred during parsing.
|
||||
func NewKeyCertificate(bytes []byte) (key_certificate *KeyCertificate, remainder []byte, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(bytes),
|
||||
}).Debug("Creating new KeyCertificate")
|
||||
|
||||
var certificate Certificate
|
||||
certificate, remainder, err = ReadCertificate(bytes)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read Certificate")
|
||||
return
|
||||
}
|
||||
if len(bytes) < KEYCERT_MIN_SIZE {
|
||||
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,
|
||||
@ -246,11 +315,25 @@ func NewKeyCertificate(bytes []byte) (key_certificate *KeyCertificate, remainder
|
||||
if len(bytes) >= 7 {
|
||||
key_certificate.cpkType = Integer(bytes[6:7])
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"spk_type": key_certificate.spkType.Int(),
|
||||
"cpk_type": key_certificate.cpkType.Int(),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully created new KeyCertificate")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// KeyCertificateFromCertificate returns a *KeyCertificate from a *Certificate.
|
||||
func KeyCertificateFromCertificate(certificate Certificate) *KeyCertificate {
|
||||
k, _, _ := NewKeyCertificate(certificate.RawBytes())
|
||||
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")
|
||||
} else {
|
||||
log.Debug("Successfully created KeyCertificate from Certificate")
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
@ -4,12 +4,16 @@ package keys_and_cert
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
|
||||
. "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/crypto"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
// Sizes of various KeysAndCert structures and requirements
|
||||
const (
|
||||
KEYS_AND_CERT_PUBKEY_SIZE = 256
|
||||
@ -80,7 +84,11 @@ type KeysAndCert struct {
|
||||
|
||||
// Bytes returns the entire KeyCertificate in []byte form, trims payload to specified length.
|
||||
func (keys_and_cert KeysAndCert) Bytes() []byte {
|
||||
return keys_and_cert.KeyCertificate.Bytes()
|
||||
bytes := keys_and_cert.KeyCertificate.Bytes()
|
||||
log.WithFields(logrus.Fields{
|
||||
"bytes_length": len(bytes),
|
||||
}).Debug("Retrieved bytes from KeysAndCert")
|
||||
return bytes
|
||||
}
|
||||
|
||||
// PublicKey returns the public key as a crypto.PublicKey.
|
||||
@ -101,10 +109,14 @@ func (keys_and_cert *KeysAndCert) Certificate() (cert Certificate) {
|
||||
// ReadKeysAndCert creates a new *KeysAndCert from []byte using ReadKeysAndCert.
|
||||
// Returns a pointer to KeysAndCert unlike ReadKeysAndCert.
|
||||
func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(data),
|
||||
}).Debug("Reading KeysAndCert from data")
|
||||
|
||||
data_len := len(data)
|
||||
// keys_and_cert = KeysAndCert{}
|
||||
if data_len < KEYS_AND_CERT_MIN_SIZE && data_len > KEYS_AND_CERT_DATA_SIZE {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "ReadKeysAndCert",
|
||||
"data_len": data_len,
|
||||
"required_len": KEYS_AND_CERT_MIN_SIZE,
|
||||
@ -114,7 +126,7 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
|
||||
keys_and_cert.KeyCertificate, remainder, _ = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
|
||||
return
|
||||
} else if data_len < KEYS_AND_CERT_DATA_SIZE {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "ReadKeysAndCert",
|
||||
"data_len": data_len,
|
||||
"required_len": KEYS_AND_CERT_MIN_SIZE,
|
||||
@ -125,6 +137,7 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
|
||||
}
|
||||
keys_and_cert.KeyCertificate, remainder, err = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
|
||||
if err != nil {
|
||||
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.
|
||||
@ -132,13 +145,23 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
|
||||
// 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()])
|
||||
if err != nil {
|
||||
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])
|
||||
if err != nil {
|
||||
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
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"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
|
||||
}
|
||||
|
@ -4,6 +4,9 @@ package lease_set
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
. "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/destination"
|
||||
@ -12,9 +15,10 @@ import (
|
||||
. "github.com/go-i2p/go-i2p/lib/common/lease"
|
||||
. "github.com/go-i2p/go-i2p/lib/common/signature"
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
// Sizes of various structures in an I2P LeaseSet
|
||||
const (
|
||||
LEASE_SET_PUBKEY_SIZE = 256
|
||||
@ -134,9 +138,15 @@ type LeaseSet struct {
|
||||
func (lease_set LeaseSet) Destination() (destination Destination, err error) {
|
||||
keys_and_cert, _, err := ReadKeysAndCert(lease_set)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read KeysAndCert from LeaseSet")
|
||||
return
|
||||
}
|
||||
destination, _, err = ReadDestination(keys_and_cert.Bytes())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read Destination from KeysAndCert")
|
||||
} else {
|
||||
log.Debug("Successfully retrieved Destination from LeaseSet")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -146,7 +156,7 @@ func (lease_set LeaseSet) PublicKey() (public_key crypto.ElgPublicKey, err error
|
||||
_, remainder, err := ReadKeysAndCert(lease_set)
|
||||
remainder_len := len(remainder)
|
||||
if remainder_len < LEASE_SET_PUBKEY_SIZE {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(LeaseSet) PublicKey",
|
||||
"data_len": remainder_len,
|
||||
"required_len": LEASE_SET_PUBKEY_SIZE,
|
||||
@ -157,25 +167,29 @@ 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")
|
||||
return
|
||||
}
|
||||
|
||||
// SigningKey returns the signing public key as crypto.SigningPublicKey.
|
||||
// returns errors encountered during parsing.
|
||||
func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicKey, err error) {
|
||||
log.Debug("Retrieving SigningKey from LeaseSet")
|
||||
destination, err := lease_set.Destination()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to retrieve Destination for SigningKey")
|
||||
return
|
||||
}
|
||||
offset := len(destination.Bytes()) + LEASE_SET_PUBKEY_SIZE
|
||||
cert := destination.Certificate()
|
||||
cert_len := cert.Length()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get Certificate length")
|
||||
return
|
||||
}
|
||||
lease_set_len := len(lease_set)
|
||||
if lease_set_len < offset+LEASE_SET_SPK_SIZE {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(LeaseSet) SigningKey",
|
||||
"data_len": lease_set_len,
|
||||
"required_len": offset + LEASE_SET_SPK_SIZE,
|
||||
@ -190,6 +204,7 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK
|
||||
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")
|
||||
} else {
|
||||
// A Certificate is present in this LeaseSet's Destination
|
||||
cert_type := cert.Type()
|
||||
@ -200,14 +215,19 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK
|
||||
signing_public_key, err = KeyCertificateFromCertificate(cert).ConstructSigningPublicKey(
|
||||
lease_set[offset : offset+LEASE_SET_SPK_SIZE],
|
||||
)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to construct SigningPublicKey from KeyCertificate")
|
||||
} else {
|
||||
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.
|
||||
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)")
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -215,13 +235,15 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK
|
||||
// LeaseCount returns the numbert of leases specified by the LeaseCount value as int.
|
||||
// returns errors encountered during parsing.
|
||||
func (lease_set LeaseSet) LeaseCount() (count int, err error) {
|
||||
log.Debug("Retrieving LeaseCount from LeaseSet")
|
||||
_, remainder, err := ReadKeysAndCert(lease_set)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read KeysAndCert for LeaseCount")
|
||||
return
|
||||
}
|
||||
remainder_len := len(remainder)
|
||||
if remainder_len < LEASE_SET_PUBKEY_SIZE+LEASE_SET_SPK_SIZE+1 {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(LeaseSet) LeaseCount",
|
||||
"data_len": remainder_len,
|
||||
"required_len": LEASE_SET_PUBKEY_SIZE + LEASE_SET_SPK_SIZE + 1,
|
||||
@ -233,12 +255,14 @@ func (lease_set LeaseSet) LeaseCount() (count int, err error) {
|
||||
c := Integer([]byte{remainder[LEASE_SET_PUBKEY_SIZE+LEASE_SET_SPK_SIZE]})
|
||||
count = c.Int()
|
||||
if count > 16 {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(LeaseSet) LeaseCount",
|
||||
"lease_count": count,
|
||||
"reason": "more than 16 leases",
|
||||
}).Warn("invalid lease set")
|
||||
err = errors.New("invalid lease set: more than 16 leases")
|
||||
} else {
|
||||
log.WithField("lease_count", count).Debug("Retrieved LeaseCount from LeaseSet")
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -246,13 +270,16 @@ func (lease_set LeaseSet) LeaseCount() (count int, err error) {
|
||||
// Leases returns the leases as []Lease.
|
||||
// returns errors encountered during parsing.
|
||||
func (lease_set LeaseSet) Leases() (leases []Lease, err error) {
|
||||
log.Debug("Retrieving Leases from LeaseSet")
|
||||
destination, err := lease_set.Destination()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to retrieve Destination for Leases")
|
||||
return
|
||||
}
|
||||
offset := len(destination.Bytes()) + LEASE_SET_PUBKEY_SIZE + LEASE_SET_SPK_SIZE + 1
|
||||
count, err := lease_set.LeaseCount()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to retrieve LeaseCount for Leases")
|
||||
return
|
||||
}
|
||||
for i := 0; i < count; i++ {
|
||||
@ -260,7 +287,7 @@ func (lease_set LeaseSet) Leases() (leases []Lease, err error) {
|
||||
end := start + LEASE_SIZE
|
||||
lease_set_len := len(lease_set)
|
||||
if lease_set_len < end {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(LeaseSet) Leases",
|
||||
"data_len": lease_set_len,
|
||||
"required_len": end,
|
||||
@ -273,18 +300,22 @@ func (lease_set LeaseSet) Leases() (leases []Lease, err error) {
|
||||
copy(lease[:], lease_set[start:end])
|
||||
leases = append(leases, lease)
|
||||
}
|
||||
log.WithField("lease_count", len(leases)).Debug("Retrieved Leases from LeaseSet")
|
||||
return
|
||||
}
|
||||
|
||||
// Signature returns the signature as Signature.
|
||||
// returns errors encountered during parsing.
|
||||
func (lease_set LeaseSet) Signature() (signature Signature, err error) {
|
||||
log.Debug("Retrieving Signature from LeaseSet")
|
||||
destination, err := lease_set.Destination()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to retrieve Destination for Signature")
|
||||
return
|
||||
}
|
||||
lease_count, err := lease_set.LeaseCount()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to retrieve LeaseCount for Signature")
|
||||
return
|
||||
}
|
||||
start := len(destination.Bytes()) +
|
||||
@ -302,7 +333,7 @@ func (lease_set LeaseSet) Signature() (signature Signature, err error) {
|
||||
}
|
||||
lease_set_len := len(lease_set)
|
||||
if lease_set_len < end {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(LeaseSet) Signature",
|
||||
"data_len": lease_set_len,
|
||||
"required_len": end,
|
||||
@ -312,11 +343,13 @@ func (lease_set LeaseSet) Signature() (signature Signature, err error) {
|
||||
return
|
||||
}
|
||||
signature = []byte(lease_set[start:end])
|
||||
log.WithField("signature_length", len(signature)).Debug("Retrieved Signature from LeaseSet")
|
||||
return
|
||||
}
|
||||
|
||||
// Verify returns nil
|
||||
func (lease_set LeaseSet) Verify() error {
|
||||
log.Debug("Verifying LeaseSet")
|
||||
//data_end := len(destination) +
|
||||
// LEASE_SET_PUBKEY_SIZE +
|
||||
// LEASE_SET_SPK_SIZE +
|
||||
@ -330,14 +363,17 @@ func (lease_set LeaseSet) Verify() error {
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
log.Warn("LeaseSet verification not implemented")
|
||||
return nil // verifier.Verify(data, lease_set.Signature())
|
||||
}
|
||||
|
||||
// NewestExpiration returns the newest lease expiration as an I2P Date.
|
||||
// Returns errors encountered during parsing.
|
||||
func (lease_set LeaseSet) NewestExpiration() (newest Date, err error) {
|
||||
log.Debug("Finding newest expiration in LeaseSet")
|
||||
leases, err := lease_set.Leases()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to retrieve Leases for NewestExpiration")
|
||||
return
|
||||
}
|
||||
newest = Date{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||
@ -347,14 +383,17 @@ func (lease_set LeaseSet) NewestExpiration() (newest Date, err error) {
|
||||
newest = date
|
||||
}
|
||||
}
|
||||
log.WithField("newest_expiration", newest.Time()).Debug("Found newest expiration in LeaseSet")
|
||||
return
|
||||
}
|
||||
|
||||
// OldestExpiration returns the oldest lease expiration as an I2P Date.
|
||||
// Returns errors encountered during parsing.
|
||||
func (lease_set LeaseSet) OldestExpiration() (earliest Date, err error) {
|
||||
log.Debug("Finding oldest expiration in LeaseSet")
|
||||
leases, err := lease_set.Leases()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to retrieve Leases for OldestExpiration")
|
||||
return
|
||||
}
|
||||
earliest = Date{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
|
||||
@ -364,5 +403,6 @@ func (lease_set LeaseSet) OldestExpiration() (earliest Date, err error) {
|
||||
earliest = date
|
||||
}
|
||||
}
|
||||
log.WithField("oldest_expiration", earliest.Time()).Debug("Found oldest expiration in LeaseSet")
|
||||
return
|
||||
}
|
||||
|
@ -8,8 +8,10 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
. "github.com/go-i2p/go-i2p/lib/common/data"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Minimum number of bytes in a valid RouterAddress
|
||||
@ -17,6 +19,8 @@ const (
|
||||
ROUTER_ADDRESS_MIN_SIZE = 9
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
/*
|
||||
[RouterAddress]
|
||||
Accurate for version 0.9.49
|
||||
@ -75,34 +79,48 @@ type RouterAddress struct {
|
||||
|
||||
// Network implements net.Addr. It returns the transport type plus 4 or 6
|
||||
func (router_address *RouterAddress) Network() string {
|
||||
log.Debug("Getting network for RouterAddress")
|
||||
if router_address.TransportType == nil {
|
||||
log.Warn("TransportType is nil in RouterAddress")
|
||||
return ""
|
||||
}
|
||||
str, err := router_address.TransportType.Data()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get TransportType data")
|
||||
return ""
|
||||
}
|
||||
return string(str) + router_address.IPVersion()
|
||||
network := string(str) + router_address.IPVersion()
|
||||
log.WithField("network", network).Debug("Retrieved network for RouterAddress")
|
||||
return network
|
||||
}
|
||||
|
||||
// IPVersion returns a string "4" for IPv4 or 6 for IPv6
|
||||
func (router_address *RouterAddress) IPVersion() string {
|
||||
log.Debug("Getting IP version for RouterAddress")
|
||||
str, err := router_address.CapsString().Data()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get CapsString data")
|
||||
return ""
|
||||
}
|
||||
if strings.HasSuffix(str, "6") {
|
||||
log.Debug("IP version is IPv6")
|
||||
return "6"
|
||||
}
|
||||
log.Debug("IP version is IPv4")
|
||||
return "4"
|
||||
}
|
||||
|
||||
func (router_address *RouterAddress) UDP() bool {
|
||||
return strings.HasPrefix(strings.ToLower(router_address.Network()), "ssu")
|
||||
// return strings.HasPrefix(strings.ToLower(router_address.Network()), "ssu")
|
||||
log.Debug("Checking if RouterAddress is UDP")
|
||||
isUDP := strings.HasPrefix(strings.ToLower(router_address.Network()), "ssu")
|
||||
log.WithField("is_udp", isUDP).Debug("Checked if RouterAddress is UDP")
|
||||
return isUDP
|
||||
}
|
||||
|
||||
// String implements net.Addr. It returns the IP address, followed by the options
|
||||
func (router_address *RouterAddress) String() string {
|
||||
log.Debug("Converting RouterAddress to string")
|
||||
var rv []string
|
||||
rv = append(rv, string(router_address.TransportStyle()))
|
||||
rv = append(rv, string(router_address.HostString()))
|
||||
@ -121,25 +139,29 @@ func (router_address *RouterAddress) String() string {
|
||||
rv = append(rv, string(router_address.IntroducerExpirationString(2)))
|
||||
rv = append(rv, string(router_address.IntroducerTagString(2)))
|
||||
}
|
||||
return strings.TrimSpace(strings.Join(rv, " "))
|
||||
str := strings.TrimSpace(strings.Join(rv, " "))
|
||||
log.WithField("router_address_string", str).Debug("Converted RouterAddress to string")
|
||||
return str
|
||||
}
|
||||
|
||||
var ex_addr net.Addr = &RouterAddress{}
|
||||
|
||||
// Bytes returns the router address as a []byte.
|
||||
func (router_address RouterAddress) Bytes() []byte {
|
||||
log.Debug("Converting RouterAddress to bytes")
|
||||
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(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Error("RouterAddress.Bytes: error getting transport_style bytes")
|
||||
} else {
|
||||
bytes = append(bytes, strData...)
|
||||
}
|
||||
bytes = append(bytes, router_address.TransportOptions.Data()...)
|
||||
log.WithField("bytes_length", len(bytes)).Debug("Converted RouterAddress to bytes")
|
||||
return bytes
|
||||
}
|
||||
|
||||
@ -224,29 +246,45 @@ func (router_address RouterAddress) IntroducerTagString(num int) I2PString {
|
||||
}
|
||||
|
||||
func (router_address RouterAddress) Host() (net.Addr, error) {
|
||||
log.Debug("Getting host from RouterAddress")
|
||||
host := router_address.HostString()
|
||||
hostBytes, err := host.Data()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get host data")
|
||||
return nil, err
|
||||
}
|
||||
ip := net.ParseIP(hostBytes)
|
||||
if ip == nil {
|
||||
log.Error("Failed to parse IP address")
|
||||
return nil, fmt.Errorf("null host error")
|
||||
}
|
||||
return net.ResolveIPAddr("", ip.String())
|
||||
// return net.ResolveIPAddr("", ip.String())
|
||||
addr, err := net.ResolveIPAddr("", ip.String())
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to resolve IP address")
|
||||
} else {
|
||||
log.WithField("addr", addr).Debug("Retrieved host from RouterAddress")
|
||||
}
|
||||
return addr, err
|
||||
}
|
||||
|
||||
func (router_address RouterAddress) Port() (string, error) {
|
||||
log.Debug("Getting port from RouterAddress")
|
||||
port := router_address.PortString()
|
||||
portBytes, err := port.Data()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get port data")
|
||||
return "", err
|
||||
}
|
||||
val, err := strconv.Atoi(portBytes)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to convert port to integer")
|
||||
return "", err
|
||||
}
|
||||
return strconv.Itoa(val), nil
|
||||
// return strconv.Itoa(val), nil
|
||||
portStr := strconv.Itoa(val)
|
||||
log.WithField("port", portStr).Debug("Retrieved port from RouterAddress")
|
||||
return portStr, nil
|
||||
}
|
||||
|
||||
func (router_address RouterAddress) StaticKey() ([32]byte, error) {
|
||||
@ -283,6 +321,7 @@ func (router_address RouterAddress) checkValid() (err error, exit bool) {
|
||||
// The remaining bytes after the specified length are also returned.
|
||||
// Returns a list of errors that occurred during parsing.
|
||||
func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []byte, err error) {
|
||||
log.WithField("data_length", len(data)).Debug("Reading RouterAddress from data")
|
||||
if len(data) == 0 {
|
||||
log.WithField("at", "(RouterAddress) ReadRouterAddress").Error("error parsing RouterAddress: no data")
|
||||
err = errors.New("error parsing RouterAddress: no data")
|
||||
@ -290,21 +329,21 @@ func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []b
|
||||
}
|
||||
router_address.TransportCost, remainder, err = NewInteger(data, 1)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(RouterAddress) ReadNewRouterAddress",
|
||||
"reason": "error parsing cost",
|
||||
}).Warn("error parsing RouterAddress")
|
||||
}
|
||||
router_address.ExpirationDate, remainder, err = NewDate(remainder)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(RouterAddress) ReadNewRouterAddress",
|
||||
"reason": "error parsing expiration",
|
||||
}).Error("error parsing RouterAddress")
|
||||
}
|
||||
router_address.TransportType, remainder, err = ReadI2PString(remainder)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(RouterAddress) ReadNewRouterAddress",
|
||||
"reason": "error parsing transport_style",
|
||||
}).Error("error parsing RouterAddress")
|
||||
@ -312,7 +351,7 @@ func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []b
|
||||
var errs []error
|
||||
router_address.TransportOptions, remainder, errs = NewMapping(remainder)
|
||||
for _, err := range errs {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(RouterAddress) ReadNewRouterAddress",
|
||||
"reason": "error parsing options",
|
||||
"error": err,
|
||||
|
@ -3,8 +3,12 @@ package router_identity
|
||||
|
||||
import (
|
||||
. "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
/*
|
||||
[RouterIdentity]
|
||||
Accurate for version 0.9.49
|
||||
@ -27,9 +31,19 @@ type RouterIdentity struct {
|
||||
// The remaining bytes after the specified length are also returned.
|
||||
// Returns a list of errors that occurred during parsing.
|
||||
func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder []byte, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(data),
|
||||
}).Debug("Reading RouterIdentity from data")
|
||||
keys_and_cert, remainder, err := ReadKeysAndCert(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read KeysAndCert for RouterIdentity")
|
||||
return
|
||||
}
|
||||
router_identity = RouterIdentity{
|
||||
keys_and_cert,
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully read RouterIdentity")
|
||||
return
|
||||
}
|
||||
|
@ -6,13 +6,17 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
. "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/common/signature"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
const ROUTER_INFO_MIN_SIZE = 439
|
||||
|
||||
const (
|
||||
@ -115,6 +119,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.published.Bytes()...)
|
||||
bytes = append(bytes, router_info.size.Bytes()...)
|
||||
@ -124,11 +129,12 @@ func (router_info RouterInfo) Bytes() (bytes []byte, err error) {
|
||||
bytes = append(bytes, router_info.peer_size.Bytes()...)
|
||||
bytes = append(bytes, router_info.options.Data()...)
|
||||
bytes = append(bytes, []byte(*router_info.signature)...)
|
||||
|
||||
log.WithField("bytes_length", len(bytes)).Debug("Converted RouterInfo to bytes")
|
||||
return bytes, err
|
||||
}
|
||||
|
||||
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())
|
||||
@ -138,6 +144,7 @@ func (router_info RouterInfo) String() string {
|
||||
str += "Peer Size: " + string(router_info.peer_size.Bytes())
|
||||
str += "Options: " + string(router_info.options.Data())
|
||||
str += "Signature: " + string([]byte(*router_info.signature))
|
||||
log.WithField("string_length", len(str)).Debug("Converted RouterInfo to string")
|
||||
return str
|
||||
}
|
||||
|
||||
@ -148,7 +155,10 @@ 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()
|
||||
hash := HashData(data)
|
||||
log.WithField("hash", hash).Debug("Calculated IdentHash for RouterInfo")
|
||||
return HashData(data)
|
||||
}
|
||||
|
||||
@ -159,11 +169,14 @@ func (router_info *RouterInfo) Published() *Date {
|
||||
|
||||
// RouterAddressCount returns the count of RouterAddress in this RouterInfo as a Go integer.
|
||||
func (router_info *RouterInfo) RouterAddressCount() int {
|
||||
return router_info.size.Int()
|
||||
count := router_info.size.Int()
|
||||
log.WithField("count", count).Debug("Retrieved RouterAddressCount from RouterInfo")
|
||||
return count
|
||||
}
|
||||
|
||||
// RouterAddresses returns all RouterAddresses for this RouterInfo as []*RouterAddress.
|
||||
func (router_info *RouterInfo) RouterAddresses() []*RouterAddress {
|
||||
log.WithField("address_count", len(router_info.addresses)).Debug("Retrieved RouterAddresses from RouterInfo")
|
||||
return router_info.addresses
|
||||
}
|
||||
|
||||
@ -193,9 +206,11 @@ func (router_info RouterInfo) Network() string {
|
||||
// The remaining bytes after the specified length are also returned.
|
||||
// Returns a list of errors that occurred during parsing.
|
||||
func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error) {
|
||||
log.WithField("input_length", len(bytes)).Debug("Reading RouterInfo from bytes")
|
||||
|
||||
info.router_identity, remainder, err = ReadRouterIdentity(bytes)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(RouterInfo) ReadRouterInfo",
|
||||
"data_len": len(bytes),
|
||||
"required_len": ROUTER_INFO_MIN_SIZE,
|
||||
@ -206,7 +221,7 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
|
||||
}
|
||||
info.published, remainder, err = NewDate(remainder)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(RouterInfo) ReadRouterInfo",
|
||||
"data_len": len(remainder),
|
||||
"required_len": DATE_SIZE,
|
||||
@ -216,7 +231,7 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
|
||||
}
|
||||
info.size, remainder, err = NewInteger(remainder, 1)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(RouterInfo) ReadRouterInfo",
|
||||
"data_len": len(remainder),
|
||||
"required_len": info.size.Int(),
|
||||
@ -227,7 +242,7 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
|
||||
address, more, err := ReadRouterAddress(remainder)
|
||||
remainder = more
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(RouterInfo) ReadRouterInfo",
|
||||
"data_len": len(remainder),
|
||||
//"required_len": ROUTER_ADDRESS_SIZE,
|
||||
@ -238,10 +253,14 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
|
||||
info.addresses = append(info.addresses, &address)
|
||||
}
|
||||
info.peer_size, remainder, err = NewInteger(remainder, 1)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read PeerSize")
|
||||
return
|
||||
}
|
||||
var errs []error
|
||||
info.options, remainder, errs = NewMapping(remainder)
|
||||
if len(errs) != 0 {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(RouterInfo) ReadRouterInfo",
|
||||
"data_len": len(remainder),
|
||||
//"required_len": MAPPING_SIZE,
|
||||
@ -255,7 +274,7 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
|
||||
}
|
||||
info.signature, remainder, err = NewSignature(remainder)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(RouterInfo) ReadRouterInfo",
|
||||
"data_len": len(remainder),
|
||||
//"required_len": MAPPING_SIZE,
|
||||
@ -263,29 +282,49 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
|
||||
}).Error("error parsing router info")
|
||||
err = errors.New("error parsing router info: not enough data")
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"router_identity": info.router_identity,
|
||||
"published": info.published,
|
||||
"address_count": len(info.addresses),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully read RouterInfo")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (router_info *RouterInfo) RouterCapabilities() string {
|
||||
log.Debug("Retrieving RouterCapabilities")
|
||||
str, err := ToI2PString("caps")
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create I2PString for 'caps'")
|
||||
return ""
|
||||
}
|
||||
return string(router_info.options.Values().Get(str))
|
||||
// return string(router_info.options.Values().Get(str))
|
||||
caps := string(router_info.options.Values().Get(str))
|
||||
log.WithField("capabilities", caps).Debug("Retrieved RouterCapabilities")
|
||||
return caps
|
||||
}
|
||||
|
||||
func (router_info *RouterInfo) RouterVersion() string {
|
||||
log.Debug("Retrieving RouterVersion")
|
||||
str, err := ToI2PString("router.version")
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create I2PString for 'router.version'")
|
||||
return ""
|
||||
}
|
||||
return string(router_info.options.Values().Get(str))
|
||||
// return string(router_info.options.Values().Get(str))
|
||||
version := string(router_info.options.Values().Get(str))
|
||||
log.WithField("version", version).Debug("Retrieved RouterVersion")
|
||||
return version
|
||||
}
|
||||
|
||||
func (router_info *RouterInfo) GoodVersion() bool {
|
||||
log.Debug("Checking if RouterVersion is good")
|
||||
version := router_info.RouterVersion()
|
||||
v := strings.Split(version, ".")
|
||||
if len(v) != 3 {
|
||||
log.WithField("version", version).Warn("Invalid version format")
|
||||
return false
|
||||
}
|
||||
if v[0] == "0" {
|
||||
@ -296,27 +335,41 @@ func (router_info *RouterInfo) GoodVersion() bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
log.WithField("version", version).Warn("Version not in good range")
|
||||
return false
|
||||
}
|
||||
|
||||
func (router_info *RouterInfo) UnCongested() bool {
|
||||
log.Debug("Checking if RouterInfo is uncongested")
|
||||
caps := router_info.RouterCapabilities()
|
||||
if strings.Contains(caps, "K") {
|
||||
log.WithField("reason", "K capability").Warn("RouterInfo is congested")
|
||||
return false
|
||||
}
|
||||
if strings.Contains(caps, "G") {
|
||||
log.WithField("reason", "G capability").Warn("RouterInfo is congested")
|
||||
return false
|
||||
}
|
||||
if strings.Contains(caps, "E") {
|
||||
log.WithField("reason", "E capability").Warn("RouterInfo is congested")
|
||||
return false
|
||||
}
|
||||
log.Debug("RouterInfo is uncongested")
|
||||
return true
|
||||
}
|
||||
|
||||
func (router_info *RouterInfo) Reachable() bool {
|
||||
log.Debug("Checking if RouterInfo is reachable")
|
||||
caps := router_info.RouterCapabilities()
|
||||
if strings.Contains(caps, "U") {
|
||||
log.WithField("reason", "U capability").Debug("RouterInfo is unreachable")
|
||||
return false
|
||||
}
|
||||
return strings.Contains(caps, "R")
|
||||
// return strings.Contains(caps, "R")
|
||||
reachable := strings.Contains(caps, "R")
|
||||
log.WithFields(logrus.Fields{
|
||||
"reachable": reachable,
|
||||
"reason": "R capability",
|
||||
}).Debug("Checked RouterInfo reachability")
|
||||
return reachable
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Package session_key implements the I2P SessionKey common data structure
|
||||
package session_key
|
||||
|
||||
import log "github.com/sirupsen/logrus"
|
||||
|
||||
/*
|
||||
[SessionKey]
|
||||
Accurate for version 0.9.49
|
||||
@ -22,13 +24,20 @@ type SessionKey [32]byte
|
||||
// Returns a list of errors that occurred during parsing.
|
||||
func ReadSessionKey(bytes []byte) (info SessionKey, remainder []byte, err error) {
|
||||
// TODO: stub
|
||||
log.Warn("ReadSessionKey is not implemented")
|
||||
return
|
||||
}
|
||||
|
||||
// NewSessionKey creates a new *SessionKey from []byte using ReadSessionKey.
|
||||
// Returns a pointer to SessionKey unlike ReadSessionKey.
|
||||
func NewSessionKey(data []byte) (session_key *SessionKey, remainder []byte, err error) {
|
||||
log.WithField("input_length", len(data)).Debug("Creating new SessionKey")
|
||||
sessionKey, remainder, err := ReadSessionKey(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new SessionKey")
|
||||
return nil, remainder, err
|
||||
}
|
||||
session_key = &sessionKey
|
||||
log.Debug("Successfully created new SessionKey")
|
||||
return
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
// Package session_tag implements the I2P SessionTag common data structure
|
||||
package session_tag
|
||||
|
||||
import (
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
/*
|
||||
[SessionKey]
|
||||
Accurate for version 0.9.49
|
||||
@ -22,13 +29,22 @@ type SessionTag [32]byte
|
||||
// Returns a list of errors that occurred during parsing.
|
||||
func ReadSessionTag(bytes []byte) (info SessionTag, remainder []byte, err error) {
|
||||
// TODO: stub
|
||||
log.Warn("ReadSessionTag is not implemented")
|
||||
return
|
||||
}
|
||||
|
||||
// NewSessionTag creates a new *SessionTag from []byte using ReadSessionTag.
|
||||
// Returns a pointer to SessionTag unlike ReadSessionTag.
|
||||
func NewSessionTag(data []byte) (session_tag *SessionTag, remainder []byte, err error) {
|
||||
log.WithField("input_length", len(data)).Debug("Creating new SessionTag")
|
||||
sessionTag, remainder, err := ReadSessionTag(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read SessionTag")
|
||||
return nil, remainder, err
|
||||
}
|
||||
session_tag = &sessionTag
|
||||
log.WithFields(logrus.Fields{
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully created new SessionTag")
|
||||
return
|
||||
}
|
||||
|
@ -1,6 +1,13 @@
|
||||
// Package signature implements the I2P Signature common data structure
|
||||
package signature
|
||||
|
||||
import (
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
// Lengths of signature keys
|
||||
const (
|
||||
DSA_SHA1_SIZE = 40
|
||||
@ -37,13 +44,25 @@ type Signature []byte
|
||||
// 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")
|
||||
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) {
|
||||
sessionTag, remainder, err := ReadSignature(data)
|
||||
session_tag = &sessionTag
|
||||
log.WithField("input_length", len(data)).Debug("Creating new Signature")
|
||||
// sessionTag, remainder, err := ReadSignature(data)
|
||||
sig, remainder, err := ReadSignature(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read Signature")
|
||||
return nil, remainder, err
|
||||
}
|
||||
session_tag = &sig
|
||||
log.WithFields(logrus.Fields{
|
||||
"signature_length": len(sig),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully created new Signature")
|
||||
|
||||
return
|
||||
}
|
||||
|
111
lib/config/config.go
Normal file
111
lib/config/config.go
Normal file
@ -0,0 +1,111 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
CfgFile string
|
||||
log = logger.GetGoI2PLogger()
|
||||
)
|
||||
|
||||
func InitConfig() {
|
||||
defaultConfigDir := filepath.Join(os.Getenv("HOME"), ".go-i2p")
|
||||
defaultConfigFile := filepath.Join(defaultConfigDir, "config.yaml")
|
||||
|
||||
if CfgFile != "" {
|
||||
// Use config file from the flag
|
||||
viper.SetConfigFile(CfgFile)
|
||||
} else {
|
||||
// Create default config if it doesn't exist
|
||||
if _, err := os.Stat(defaultConfigFile); os.IsNotExist(err) {
|
||||
// Ensure directory exists
|
||||
if err := os.MkdirAll(defaultConfigDir, 0o755); err != nil {
|
||||
log.Fatalf("Could not create config directory: %s", err)
|
||||
}
|
||||
|
||||
// Create default configuration
|
||||
defaultConfig := struct {
|
||||
BaseDir string `yaml:"base_dir"`
|
||||
WorkingDir string `yaml:"working_dir"`
|
||||
NetDB NetDbConfig `yaml:"netdb"`
|
||||
Bootstrap BootstrapConfig `yaml:"bootstrap"`
|
||||
}{
|
||||
BaseDir: DefaultRouterConfig().BaseDir,
|
||||
WorkingDir: DefaultRouterConfig().WorkingDir,
|
||||
NetDB: *DefaultRouterConfig().NetDb,
|
||||
Bootstrap: *DefaultRouterConfig().Bootstrap,
|
||||
}
|
||||
|
||||
yamlData, err := yaml.Marshal(defaultConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not marshal default config: %s", err)
|
||||
}
|
||||
|
||||
// Write default config file
|
||||
if err := os.WriteFile(defaultConfigFile, yamlData, 0o644); err != nil {
|
||||
log.Fatalf("Could not write default config file: %s", err)
|
||||
}
|
||||
|
||||
log.Debugf("Created default configuration at: %s", defaultConfigFile)
|
||||
}
|
||||
|
||||
// Set up viper to use the config file
|
||||
viper.AddConfigPath(defaultConfigDir)
|
||||
viper.SetConfigName("config")
|
||||
viper.SetConfigType("yaml")
|
||||
}
|
||||
|
||||
// Load defaults
|
||||
setDefaults()
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
log.Warnf("Error reading config file: %s", err)
|
||||
} else {
|
||||
log.Debugf("Using config file: %s", viper.ConfigFileUsed())
|
||||
}
|
||||
|
||||
// Update RouterConfigProperties
|
||||
UpdateRouterConfig()
|
||||
}
|
||||
|
||||
func setDefaults() {
|
||||
// Router defaults
|
||||
viper.SetDefault("base_dir", DefaultRouterConfig().BaseDir)
|
||||
viper.SetDefault("working_dir", DefaultRouterConfig().WorkingDir)
|
||||
|
||||
// NetDb defaults
|
||||
viper.SetDefault("netdb.path", DefaultNetDbConfig.Path)
|
||||
|
||||
// Bootstrap defaults
|
||||
viper.SetDefault("bootstrap.low_peer_threshold", DefaultBootstrapConfig.LowPeerThreshold)
|
||||
viper.SetDefault("bootstrap.reseed_servers", []ReseedConfig{})
|
||||
}
|
||||
|
||||
func UpdateRouterConfig() {
|
||||
// Update Router configuration
|
||||
RouterConfigProperties.BaseDir = viper.GetString("base_dir")
|
||||
RouterConfigProperties.WorkingDir = viper.GetString("working_dir")
|
||||
|
||||
// Update NetDb configuration
|
||||
RouterConfigProperties.NetDb = &NetDbConfig{
|
||||
Path: viper.GetString("netdb.path"),
|
||||
}
|
||||
|
||||
// Update Bootstrap configuration
|
||||
var reseedServers []*ReseedConfig
|
||||
if err := viper.UnmarshalKey("bootstrap.reseed_servers", &reseedServers); err != nil {
|
||||
log.Warnf("Error parsing reseed servers: %s", err)
|
||||
reseedServers = []*ReseedConfig{}
|
||||
}
|
||||
|
||||
RouterConfigProperties.Bootstrap = &BootstrapConfig{
|
||||
LowPeerThreshold: viper.GetInt("bootstrap.low_peer_threshold"),
|
||||
ReseedServers: reseedServers,
|
||||
}
|
||||
}
|
@ -1 +1,177 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
// AESSymmetricKey represents a symmetric key for AES encryption/decryption
|
||||
type AESSymmetricKey struct {
|
||||
Key []byte // AES key (must be 16, 24, or 32 bytes for AES-128, AES-192, AES-256)
|
||||
IV []byte // Initialization Vector (must be 16 bytes for AES)
|
||||
}
|
||||
|
||||
// AESSymmetricEncrypter implements the Encrypter interface using AES
|
||||
type AESSymmetricEncrypter struct {
|
||||
Key []byte
|
||||
IV []byte
|
||||
}
|
||||
|
||||
// Encrypt encrypts data using AES-CBC with PKCS#7 padding
|
||||
func (e *AESSymmetricEncrypter) Encrypt(data []byte) ([]byte, error) {
|
||||
log.WithField("data_length", len(data)).Debug("Encrypting data")
|
||||
|
||||
block, err := aes.NewCipher(e.Key)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create AES cipher")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plaintext := pkcs7Pad(data, aes.BlockSize)
|
||||
ciphertext := make([]byte, len(plaintext))
|
||||
mode := cipher.NewCBCEncrypter(block, e.IV)
|
||||
mode.CryptBlocks(ciphertext, plaintext)
|
||||
|
||||
log.WithField("ciphertext_length", len(ciphertext)).Debug("Data encrypted successfully")
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
// AESSymmetricDecrypter implements the Decrypter interface using AES
|
||||
type AESSymmetricDecrypter struct {
|
||||
Key []byte
|
||||
IV []byte
|
||||
}
|
||||
|
||||
// Decrypt decrypts data using AES-CBC with PKCS#7 padding
|
||||
func (d *AESSymmetricDecrypter) Decrypt(data []byte) ([]byte, error) {
|
||||
log.WithField("data_length", len(data)).Debug("Decrypting data")
|
||||
|
||||
block, err := aes.NewCipher(d.Key)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create AES cipher")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(data)%aes.BlockSize != 0 {
|
||||
log.Error("Ciphertext is not a multiple of the block size")
|
||||
return nil, fmt.Errorf("ciphertext is not a multiple of the block size")
|
||||
}
|
||||
|
||||
plaintext := make([]byte, len(data))
|
||||
mode := cipher.NewCBCDecrypter(block, d.IV)
|
||||
mode.CryptBlocks(plaintext, data)
|
||||
|
||||
plaintext, err = pkcs7Unpad(plaintext)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to unpad plaintext")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.WithField("plaintext_length", len(plaintext)).Debug("Data decrypted successfully")
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
// NewEncrypter creates a new AESSymmetricEncrypter
|
||||
func (k *AESSymmetricKey) NewEncrypter() (Encrypter, error) {
|
||||
log.Debug("Creating new AESSymmetricEncrypter")
|
||||
return &AESSymmetricEncrypter{
|
||||
Key: k.Key,
|
||||
IV: k.IV,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Len returns the length of the key
|
||||
func (k *AESSymmetricKey) Len() int {
|
||||
return len(k.Key)
|
||||
}
|
||||
|
||||
// NewDecrypter creates a new AESSymmetricDecrypter
|
||||
func (k *AESSymmetricKey) NewDecrypter() (Decrypter, error) {
|
||||
return &AESSymmetricDecrypter{
|
||||
Key: k.Key,
|
||||
IV: k.IV,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func pkcs7Pad(data []byte, blockSize int) []byte {
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
"block_size": blockSize,
|
||||
}).Debug("Applying PKCS#7 padding")
|
||||
|
||||
padding := blockSize - (len(data) % blockSize)
|
||||
padText := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
padded := append(data, padText...)
|
||||
|
||||
log.WithField("padded_length", len(padded)).Debug("PKCS#7 padding applied")
|
||||
return append(data, padText...)
|
||||
}
|
||||
|
||||
func pkcs7Unpad(data []byte) ([]byte, error) {
|
||||
log.WithField("data_length", len(data)).Debug("Removing PKCS#7 padding")
|
||||
|
||||
length := len(data)
|
||||
if length == 0 {
|
||||
log.Error("Data is empty")
|
||||
return nil, fmt.Errorf("data is empty")
|
||||
}
|
||||
padding := int(data[length-1])
|
||||
if padding == 0 || padding > aes.BlockSize {
|
||||
log.WithField("padding", padding).Error("Invalid padding")
|
||||
return nil, fmt.Errorf("invalid padding")
|
||||
}
|
||||
paddingStart := length - padding
|
||||
for i := paddingStart; i < length; i++ {
|
||||
if data[i] != byte(padding) {
|
||||
log.Error("Invalid padding")
|
||||
return nil, fmt.Errorf("invalid padding")
|
||||
}
|
||||
}
|
||||
|
||||
unpadded := data[:paddingStart]
|
||||
log.WithField("unpadded_length", len(unpadded)).Debug("PKCS#7 padding removed")
|
||||
return unpadded, nil
|
||||
}
|
||||
|
||||
// EncryptNoPadding encrypts data using AES-CBC without padding
|
||||
func (e *AESSymmetricEncrypter) EncryptNoPadding(data []byte) ([]byte, error) {
|
||||
if len(data)%aes.BlockSize != 0 {
|
||||
return nil, fmt.Errorf("data length must be a multiple of block size")
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(e.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ciphertext := make([]byte, len(data))
|
||||
mode := cipher.NewCBCEncrypter(block, e.IV)
|
||||
mode.CryptBlocks(ciphertext, data)
|
||||
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
// DecryptNoPadding decrypts data using AES-CBC without padding
|
||||
func (d *AESSymmetricDecrypter) DecryptNoPadding(data []byte) ([]byte, error) {
|
||||
if len(data)%aes.BlockSize != 0 {
|
||||
return nil, fmt.Errorf("data length must be a multiple of block size")
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(d.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plaintext := make([]byte, len(data))
|
||||
mode := cipher.NewCBCDecrypter(block, d.IV)
|
||||
mode.CryptBlocks(plaintext, data)
|
||||
|
||||
return plaintext, nil
|
||||
}
|
||||
|
182
lib/crypto/aes_test.go
Normal file
182
lib/crypto/aes_test.go
Normal file
@ -0,0 +1,182 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAESEncryptDecrypt(t *testing.T) {
|
||||
key := make([]byte, 32) // 256-bit key
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
_, err := rand.Read(key)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate random key: %v", err)
|
||||
}
|
||||
_, err = rand.Read(iv)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate random IV: %v", err)
|
||||
}
|
||||
|
||||
symmetricKey := AESSymmetricKey{
|
||||
Key: key,
|
||||
IV: iv,
|
||||
}
|
||||
|
||||
encrypter, err := symmetricKey.NewEncrypter()
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating encrypter: %v", err)
|
||||
}
|
||||
|
||||
decrypter, err := symmetricKey.NewDecrypter()
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating decrypter: %v", err)
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
plaintext []byte
|
||||
}{
|
||||
{"Empty string", []byte("")},
|
||||
{"Short string", []byte("Hello, World!")},
|
||||
{"Long string", bytes.Repeat([]byte("A"), 1000)},
|
||||
{"Exact block size", bytes.Repeat([]byte("A"), aes.BlockSize)},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ciphertext, err := encrypter.Encrypt(tc.plaintext)
|
||||
if err != nil {
|
||||
t.Fatalf("Encryption failed: %v", err)
|
||||
}
|
||||
|
||||
decrypted, err := decrypter.Decrypt(ciphertext)
|
||||
if err != nil {
|
||||
t.Fatalf("Decryption failed: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(tc.plaintext, decrypted) {
|
||||
t.Errorf("Decrypted text doesn't match original plaintext.\nOriginal: %s\nDecrypted: %s",
|
||||
hex.EncodeToString(tc.plaintext), hex.EncodeToString(decrypted))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAESEncryptInvalidKey(t *testing.T) {
|
||||
invalidKeys := [][]byte{
|
||||
make([]byte, 15), // Too short
|
||||
make([]byte, 17), // Invalid length
|
||||
make([]byte, 31), // Too short for AES-256
|
||||
make([]byte, 33), // Too long
|
||||
make([]byte, 0), // Empty
|
||||
nil, // Nil
|
||||
}
|
||||
|
||||
plaintext := []byte("Test plaintext")
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
_, _ = rand.Read(iv)
|
||||
|
||||
for _, key := range invalidKeys {
|
||||
symmetricKey := &AESSymmetricKey{
|
||||
Key: key,
|
||||
IV: iv,
|
||||
}
|
||||
encrypter, err := symmetricKey.NewEncrypter()
|
||||
if err == nil {
|
||||
_, err = encrypter.Encrypt(plaintext)
|
||||
}
|
||||
if err == nil {
|
||||
t.Errorf("Expected error for invalid key length %d, but got none", len(key))
|
||||
} else {
|
||||
t.Logf("Correctly got error for key length %d: %v", len(key), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAESDecryptInvalidInput(t *testing.T) {
|
||||
key := make([]byte, 32) // Valid key length for AES-256
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
_, _ = rand.Read(key)
|
||||
_, _ = rand.Read(iv)
|
||||
|
||||
symmetricKey := &AESSymmetricKey{
|
||||
Key: key,
|
||||
IV: iv,
|
||||
}
|
||||
decrypter, err := symmetricKey.NewDecrypter()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create decrypter: %v", err)
|
||||
}
|
||||
|
||||
invalidCiphertexts := [][]byte{
|
||||
make([]byte, 15), // Not a multiple of block size
|
||||
make([]byte, 0), // Empty
|
||||
nil, // Nil
|
||||
}
|
||||
|
||||
for _, ciphertext := range invalidCiphertexts {
|
||||
_, err := decrypter.Decrypt(ciphertext)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error for invalid ciphertext length %d, but got none", len(ciphertext))
|
||||
} else {
|
||||
t.Logf("Correctly got error for ciphertext length %d: %v", len(ciphertext), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPKCS7PadUnpad(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
input []byte
|
||||
blockSize int
|
||||
}{
|
||||
{"Empty input", []byte{}, 16},
|
||||
{"Exact block size", bytes.Repeat([]byte("A"), 16), 16},
|
||||
{"One byte short", bytes.Repeat([]byte("A"), 15), 16},
|
||||
{"Multiple blocks", bytes.Repeat([]byte("A"), 32), 16},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
padded := pkcs7Pad(tc.input, tc.blockSize)
|
||||
if len(padded)%tc.blockSize != 0 {
|
||||
t.Errorf("Padded data length (%d) is not a multiple of block size (%d)", len(padded), tc.blockSize)
|
||||
}
|
||||
|
||||
unpadded, err := pkcs7Unpad(padded)
|
||||
if err != nil {
|
||||
t.Fatalf("Unpadding failed: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(tc.input, unpadded) {
|
||||
t.Errorf("Unpadded data doesn't match original input.\nOriginal: %s\nUnpadded: %s",
|
||||
hex.EncodeToString(tc.input), hex.EncodeToString(unpadded))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPKCS7UnpadInvalidInput(t *testing.T) {
|
||||
invalidInputs := []struct {
|
||||
name string
|
||||
input []byte
|
||||
}{
|
||||
{"Empty slice", []byte{}},
|
||||
{"Invalid padding value", []byte{1, 2, 3, 4, 0}}, // Padding value 0 is invalid
|
||||
{"Padding larger than block size", append(bytes.Repeat([]byte{17}, 17))}, // Padding value 17 (>16) is invalid
|
||||
{"Incorrect padding bytes", []byte{1, 2, 3, 4, 5, 6, 2, 3, 3}}, // Last padding bytes do not match padding value
|
||||
{"Valid block size but invalid padding", append(bytes.Repeat([]byte{1}, 15), 3)}, // Padding value 3, but bytes are 1
|
||||
}
|
||||
|
||||
for _, tc := range invalidInputs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
_, err := pkcs7Unpad(tc.input)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error for invalid input %v, but got none", tc.input)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -8,6 +8,8 @@ import (
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
curve25519 "go.step.sm/crypto/x25519"
|
||||
)
|
||||
|
||||
@ -27,14 +29,20 @@ func (k Curve25519PublicKey) NewVerifier() (v Verifier, err error) {
|
||||
}
|
||||
|
||||
func (k Curve25519PublicKey) Len() int {
|
||||
return len(k)
|
||||
length := len(k)
|
||||
log.WithField("length", length).Debug("Retrieved Curve25519PublicKey length")
|
||||
return length
|
||||
}
|
||||
|
||||
func createCurve25519PublicKey(data []byte) (k *curve25519.PublicKey) {
|
||||
log.WithField("data_length", len(data)).Debug("Creating Curve25519PublicKey")
|
||||
if len(data) == 256 {
|
||||
k2 := curve25519.PublicKey{}
|
||||
copy(k2[:], data)
|
||||
k = &k2
|
||||
log.Debug("Curve25519PublicKey created successfully")
|
||||
} else {
|
||||
log.Warn("Invalid data length for Curve25519PublicKey")
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -53,6 +61,7 @@ func createCurve25519Encryption(pub *curve25519.PublicKey, rand io.Reader) (enc
|
||||
if err == nil {
|
||||
enc = &Curve25519Encryption{}
|
||||
}*/
|
||||
log.Warn("createCurve25519Encryption is not implemented")
|
||||
return
|
||||
}
|
||||
|
||||
@ -61,11 +70,17 @@ type Curve25519Encryption struct {
|
||||
}
|
||||
|
||||
func (curve25519 *Curve25519Encryption) Encrypt(data []byte) (enc []byte, err error) {
|
||||
log.WithField("data_length", len(data)).Debug("Encrypting data with Curve25519")
|
||||
return curve25519.EncryptPadding(data, true)
|
||||
}
|
||||
|
||||
func (curve25519 *Curve25519Encryption) EncryptPadding(data []byte, zeroPadding bool) (encrypted []byte, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
"zero_padding": zeroPadding,
|
||||
}).Debug("Encrypting data with padding using Curve25519")
|
||||
if len(data) > 222 {
|
||||
log.Error("Data too big for Curve25519 encryption")
|
||||
err = Curve25519EncryptTooBig
|
||||
return
|
||||
}
|
||||
@ -88,33 +103,55 @@ func (curve25519 *Curve25519Encryption) EncryptPadding(data []byte, zeroPadding
|
||||
copy(encrypted, curve25519.a.Bytes())
|
||||
copy(encrypted[256:], b)
|
||||
}
|
||||
log.WithField("encrypted_length", len(encrypted)).Debug("Data encrypted successfully")
|
||||
return
|
||||
}
|
||||
|
||||
func (elg Curve25519PublicKey) NewEncrypter() (enc Encrypter, err error) {
|
||||
log.Debug("Creating new Curve25519 Encrypter")
|
||||
k := createCurve25519PublicKey(elg[:])
|
||||
enc, err = createCurve25519Encryption(k, rand.Reader)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Curve25519 Encrypter")
|
||||
} else {
|
||||
log.Debug("Curve25519 Encrypter created successfully")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (v *Curve25519Verifier) VerifyHash(h, sig []byte) (err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"hash_length": len(h),
|
||||
"signature_length": len(sig),
|
||||
}).Debug("Verifying hash with Curve25519")
|
||||
|
||||
if len(sig) != curve25519.SignatureSize {
|
||||
log.Error("Bad signature size")
|
||||
err = ErrBadSignatureSize
|
||||
return
|
||||
}
|
||||
if len(v.k) != curve25519.PublicKeySize {
|
||||
log.Error("Invalid Curve25519 public key size")
|
||||
err = errors.New("failed to verify: invalid curve25519 public key size")
|
||||
return
|
||||
}
|
||||
|
||||
ok := curve25519.Verify(v.k, h, sig)
|
||||
if !ok {
|
||||
log.Error("Invalid signature")
|
||||
err = errors.New("failed to verify: invalid signature")
|
||||
} else {
|
||||
log.Debug("Hash verified successfully")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (v *Curve25519Verifier) Verify(data, sig []byte) (err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
"signature_length": len(sig),
|
||||
}).Debug("Verifying data with Curve25519")
|
||||
|
||||
h := sha512.Sum512(data)
|
||||
err = v.VerifyHash(h[:], sig)
|
||||
return
|
||||
@ -127,15 +164,31 @@ type Curve25519Signer struct {
|
||||
}
|
||||
|
||||
func (s *Curve25519Signer) Sign(data []byte) (sig []byte, err error) {
|
||||
log.WithField("data_length", len(data)).Debug("Signing data with Curve25519")
|
||||
|
||||
if len(s.k) != curve25519.PrivateKeySize {
|
||||
log.Error("Invalid Curve25519 private key size")
|
||||
err = errors.New("failed to sign: invalid curve25519 private key size")
|
||||
return
|
||||
}
|
||||
h := sha512.Sum512(data)
|
||||
sig, err = s.SignHash(h[:])
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to sign data")
|
||||
} else {
|
||||
log.WithField("signature_length", len(sig)).Debug("Data signed successfully")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Curve25519Signer) SignHash(h []byte) (sig []byte, err error) {
|
||||
return curve25519.Sign(rand.Reader, s.k, h)
|
||||
log.WithField("hash_length", len(h)).Debug("Signing hash with Curve25519")
|
||||
sig, err = curve25519.Sign(rand.Reader, s.k, h)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to sign hash")
|
||||
} else {
|
||||
log.WithField("signature_length", len(sig)).Debug("Hash signed successfully")
|
||||
}
|
||||
// return curve25519.Sign(rand.Reader, s.k, h)
|
||||
return
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
--
|
||||
import "github.com/go-i2p/go-i2p/lib/crypto"
|
||||
|
||||
package for i2p specific crpytography
|
||||
package for i2p specific cryptography
|
||||
|
||||
## Usage
|
||||
|
||||
@ -12,7 +12,72 @@ const (
|
||||
OPAD = byte(0x5C)
|
||||
)
|
||||
```
|
||||
#### type AESSymmetricKey
|
||||
```go
|
||||
type AESSymmetricKey struct {
|
||||
Key []byte // AES key (must be 16, 24, or 32 bytes for AES-128, AES-192, AES-256)
|
||||
IV []byte // Initialization Vector (must be 16 bytes for AES)
|
||||
}
|
||||
```
|
||||
|
||||
AESSymmetricKey represents a symmetric key for AES encryption/decryption
|
||||
|
||||
#### func (AESSymmetricKey) NewEncrypter
|
||||
|
||||
```go
|
||||
func (k *AESSymmetricKey) NewEncrypter() (Encrypter, error)
|
||||
```
|
||||
NewEncrypter creates a new AESSymmetricEncrypter
|
||||
|
||||
#### func (AESSymmetricKey) NewDecrypter
|
||||
|
||||
```go
|
||||
func (k *AESSymmetricKey) NewDecrypter() (Decrypter, error)
|
||||
```
|
||||
NewDecrypter creates a new AESSymmetricDecrypter
|
||||
|
||||
#### func (AESSymmetricKey) Len
|
||||
|
||||
```go
|
||||
func (k *AESSymmetricKey) Len() int
|
||||
```
|
||||
Len returns the length of the key
|
||||
|
||||
#### type AESSymmetricEncrypter
|
||||
|
||||
```go
|
||||
type AESSymmetricEncrypter struct {
|
||||
Key []byte
|
||||
IV []byte
|
||||
}
|
||||
```
|
||||
|
||||
AESSymmetricEncrypter implements the Encrypter interface using AES
|
||||
|
||||
#### func (*AESSymmetricEncrypter) Encrypt
|
||||
|
||||
```go
|
||||
func (e *AESSymmetricEncrypter) Encrypt(data []byte) ([]byte, error)
|
||||
```
|
||||
Encrypt encrypts data using AES-CBC with PKCS#7 padding
|
||||
|
||||
#### type AESSymmetricDecrypter
|
||||
|
||||
```go
|
||||
type AESSymmetricDecrypter struct {
|
||||
Key []byte
|
||||
IV []byte
|
||||
}
|
||||
```
|
||||
|
||||
AESSymmetricDecrypter implements the Decrypter interface using AES
|
||||
|
||||
#### func (*AESSymmetricDecrypter) Decrypt
|
||||
|
||||
```go
|
||||
func (d *AESSymmetricDecrypter) Decrypt(data []byte) ([]byte, error)
|
||||
```
|
||||
Decrypt decrypts data using AES-CBC with PKCS#7 padding
|
||||
```go
|
||||
var (
|
||||
ElgDecryptFail = errors.New("failed to decrypt elgamal encrypted data")
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"crypto/sha1"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var dsap = new(big.Int).SetBytes([]byte{
|
||||
@ -43,16 +45,24 @@ var param = dsa.Parameters{
|
||||
|
||||
// generate a dsa keypair
|
||||
func generateDSA(priv *dsa.PrivateKey, rand io.Reader) error {
|
||||
log.Debug("Generating DSA key pair")
|
||||
// put our paramters in
|
||||
priv.P = param.P
|
||||
priv.Q = param.Q
|
||||
priv.G = param.G
|
||||
// generate the keypair
|
||||
return dsa.GenerateKey(priv, rand)
|
||||
err := dsa.GenerateKey(priv, rand)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to generate DSA key pair")
|
||||
} else {
|
||||
log.Debug("DSA key pair generated successfully")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// create i2p dsa public key given its public component
|
||||
func createDSAPublicKey(Y *big.Int) *dsa.PublicKey {
|
||||
log.Debug("Creating DSA public key")
|
||||
return &dsa.PublicKey{
|
||||
Parameters: param,
|
||||
Y: Y,
|
||||
@ -61,6 +71,7 @@ func createDSAPublicKey(Y *big.Int) *dsa.PublicKey {
|
||||
|
||||
// createa i2p dsa private key given its public component
|
||||
func createDSAPrivkey(X *big.Int) (k *dsa.PrivateKey) {
|
||||
log.Debug("Creating DSA private key")
|
||||
if X.Cmp(dsap) == -1 {
|
||||
Y := new(big.Int)
|
||||
Y.Exp(dsag, X, dsap)
|
||||
@ -71,6 +82,9 @@ func createDSAPrivkey(X *big.Int) (k *dsa.PrivateKey) {
|
||||
},
|
||||
X: X,
|
||||
}
|
||||
log.Debug("DSA private key created successfully")
|
||||
} else {
|
||||
log.Warn("Failed to create DSA private key: X is not less than p")
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -83,6 +97,7 @@ type DSAPublicKey [128]byte
|
||||
|
||||
// create a new dsa verifier
|
||||
func (k DSAPublicKey) NewVerifier() (v Verifier, err error) {
|
||||
log.Debug("Creating new DSA verifier")
|
||||
v = &DSAVerifier{
|
||||
k: createDSAPublicKey(new(big.Int).SetBytes(k[:])),
|
||||
}
|
||||
@ -91,6 +106,10 @@ func (k DSAPublicKey) NewVerifier() (v Verifier, err error) {
|
||||
|
||||
// verify data with a dsa public key
|
||||
func (v *DSAVerifier) Verify(data, sig []byte) (err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
"sig_length": len(sig),
|
||||
}).Debug("Verifying DSA signature")
|
||||
h := sha1.Sum(data)
|
||||
err = v.VerifyHash(h[:], sig)
|
||||
return
|
||||
@ -98,16 +117,23 @@ func (v *DSAVerifier) Verify(data, sig []byte) (err error) {
|
||||
|
||||
// verify hash of data with a dsa public key
|
||||
func (v *DSAVerifier) VerifyHash(h, sig []byte) (err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"hash_length": len(h),
|
||||
"sig_length": len(sig),
|
||||
}).Debug("Verifying DSA signature hash")
|
||||
if len(sig) == 40 {
|
||||
r := new(big.Int).SetBytes(sig[:20])
|
||||
s := new(big.Int).SetBytes(sig[20:])
|
||||
if dsa.Verify(v.k, h, r, s) {
|
||||
// valid signature
|
||||
log.Debug("DSA signature verified successfully")
|
||||
} else {
|
||||
// invalid signature
|
||||
log.Warn("Invalid DSA signature")
|
||||
err = ErrInvalidSignature
|
||||
}
|
||||
} else {
|
||||
log.Error("Bad DSA signature size")
|
||||
err = ErrBadSignatureSize
|
||||
}
|
||||
return
|
||||
@ -125,6 +151,7 @@ type DSAPrivateKey [20]byte
|
||||
|
||||
// create a new dsa signer
|
||||
func (k DSAPrivateKey) NewSigner() (s Signer, err error) {
|
||||
log.Debug("Creating new DSA signer")
|
||||
s = &DSASigner{
|
||||
k: createDSAPrivkey(new(big.Int).SetBytes(k[:])),
|
||||
}
|
||||
@ -134,30 +161,38 @@ func (k DSAPrivateKey) NewSigner() (s Signer, err error) {
|
||||
func (k DSAPrivateKey) Public() (pk DSAPublicKey, err error) {
|
||||
p := createDSAPrivkey(new(big.Int).SetBytes(k[:]))
|
||||
if p == nil {
|
||||
log.Error("Invalid DSA private key format")
|
||||
err = ErrInvalidKeyFormat
|
||||
} else {
|
||||
copy(pk[:], p.Y.Bytes())
|
||||
log.Debug("DSA public key derived successfully")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (k DSAPrivateKey) Generate() (s DSAPrivateKey, err error) {
|
||||
log.Debug("Generating new DSA private key")
|
||||
dk := new(dsa.PrivateKey)
|
||||
err = generateDSA(dk, rand.Reader)
|
||||
if err == nil {
|
||||
copy(k[:], dk.X.Bytes())
|
||||
s = k
|
||||
log.Debug("New DSA private key generated successfully")
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to generate new DSA private key")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ds *DSASigner) Sign(data []byte) (sig []byte, err error) {
|
||||
log.WithField("data_length", len(data)).Debug("Signing data with DSA")
|
||||
h := sha1.Sum(data)
|
||||
sig, err = ds.SignHash(h[:])
|
||||
return
|
||||
}
|
||||
|
||||
func (ds *DSASigner) SignHash(h []byte) (sig []byte, err error) {
|
||||
log.WithField("hash_length", len(h)).Debug("Signing hash with DSA")
|
||||
var r, s *big.Int
|
||||
r, s, err = dsa.Sign(rand.Reader, ds.k, h)
|
||||
if err == nil {
|
||||
@ -168,6 +203,9 @@ func (ds *DSASigner) SignHash(h []byte) (sig []byte, err error) {
|
||||
sb := s.Bytes()
|
||||
sl := len(sb)
|
||||
copy(sig[20+(20-sl):], sb)
|
||||
log.WithField("sig_length", len(sig)).Debug("DSA signature created successfully")
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to create DSA signature")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -4,8 +4,6 @@ import (
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func TestDSA(t *testing.T) {
|
||||
@ -86,5 +84,5 @@ func BenchmarkDSASignVerify(b *testing.B) {
|
||||
fail++
|
||||
}
|
||||
}
|
||||
log.Infof("%d fails %d signs", fail, b.N)
|
||||
log.Debugf("%d fails %d signs", fail, b.N)
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type ECDSAVerifier struct {
|
||||
@ -14,15 +16,27 @@ type ECDSAVerifier struct {
|
||||
|
||||
// verify a signature given the hash
|
||||
func (v *ECDSAVerifier) VerifyHash(h, sig []byte) (err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"hash_length": len(h),
|
||||
"sig_length": len(sig),
|
||||
}).Debug("Verifying ECDSA signature hash")
|
||||
|
||||
r, s := elliptic.Unmarshal(v.c, sig)
|
||||
if r == nil || s == nil || !ecdsa.Verify(v.k, h, r, s) {
|
||||
log.Warn("Invalid ECDSA signature")
|
||||
err = ErrInvalidSignature
|
||||
} else {
|
||||
log.Debug("ECDSA signature verified successfully")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// verify a block of data by hashing it and comparing the hash against the signature
|
||||
func (v *ECDSAVerifier) Verify(data, sig []byte) (err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
"sig_length": len(sig),
|
||||
}).Debug("Verifying ECDSA signature")
|
||||
// sum the data and get the hash
|
||||
h := v.h.New().Sum(data)[len(data):]
|
||||
// verify
|
||||
@ -31,8 +45,13 @@ func (v *ECDSAVerifier) Verify(data, sig []byte) (err error) {
|
||||
}
|
||||
|
||||
func createECVerifier(c elliptic.Curve, h crypto.Hash, k []byte) (ev *ECDSAVerifier, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"curve": c.Params().Name,
|
||||
"hash": h.String(),
|
||||
}).Debug("Creating ECDSA verifier")
|
||||
x, y := elliptic.Unmarshal(c, k[:])
|
||||
if x == nil {
|
||||
log.Error("Invalid ECDSA key format")
|
||||
err = ErrInvalidKeyFormat
|
||||
} else {
|
||||
ev = &ECDSAVerifier{
|
||||
@ -40,6 +59,7 @@ func createECVerifier(c elliptic.Curve, h crypto.Hash, k []byte) (ev *ECDSAVerif
|
||||
h: h,
|
||||
}
|
||||
ev.k = &ecdsa.PublicKey{c, x, y}
|
||||
log.Debug("ECDSA verifier created successfully")
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -54,7 +74,13 @@ func (k ECP256PublicKey) Len() int {
|
||||
}
|
||||
|
||||
func (k ECP256PublicKey) NewVerifier() (Verifier, error) {
|
||||
return createECVerifier(elliptic.P256(), crypto.SHA256, k[:])
|
||||
log.Debug("Creating new P256 ECDSA verifier")
|
||||
// return createECVerifier(elliptic.P256(), crypto.SHA256, k[:])
|
||||
v, err := createECVerifier(elliptic.P256(), crypto.SHA256, k[:])
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create P256 ECDSA verifier")
|
||||
}
|
||||
return v, err
|
||||
}
|
||||
|
||||
type (
|
||||
@ -67,7 +93,13 @@ func (k ECP384PublicKey) Len() int {
|
||||
}
|
||||
|
||||
func (k ECP384PublicKey) NewVerifier() (Verifier, error) {
|
||||
return createECVerifier(elliptic.P384(), crypto.SHA384, k[:])
|
||||
log.Debug("Creating new P384 ECDSA verifier")
|
||||
v, err := createECVerifier(elliptic.P384(), crypto.SHA384, k[:])
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create P384 ECDSA verifier")
|
||||
}
|
||||
return v, err
|
||||
// return createECVerifier(elliptic.P384(), crypto.SHA384, k[:])
|
||||
}
|
||||
|
||||
type (
|
||||
@ -80,5 +112,11 @@ func (k ECP521PublicKey) Len() int {
|
||||
}
|
||||
|
||||
func (k ECP521PublicKey) NewVerifier() (Verifier, error) {
|
||||
return createECVerifier(elliptic.P521(), crypto.SHA512, k[:])
|
||||
log.Debug("Creating new P521 ECDSA verifier")
|
||||
v, err := createECVerifier(elliptic.P521(), crypto.SHA512, k[:])
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create P521 ECDSA verifier")
|
||||
}
|
||||
return v, err
|
||||
// return createECVerifier(elliptic.P521(), crypto.SHA512, k[:])
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var Ed25519EncryptTooBig = errors.New("failed to encrypt data, too big for Ed25519")
|
||||
@ -30,10 +32,14 @@ func (k Ed25519PublicKey) Len() int {
|
||||
}
|
||||
|
||||
func createEd25519PublicKey(data []byte) (k *ed25519.PublicKey) {
|
||||
log.WithField("data_length", len(data)).Debug("Creating Ed25519 public key")
|
||||
if len(data) == 256 {
|
||||
k2 := ed25519.PublicKey{}
|
||||
copy(k2[:], data)
|
||||
k = &k2
|
||||
log.Debug("Ed25519 public key created successfully")
|
||||
} else {
|
||||
log.Warn("Invalid data length for Ed25519 public key")
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -52,6 +58,7 @@ func createEd25519Encryption(pub *ed25519.PublicKey, rand io.Reader) (enc *Ed255
|
||||
if err == nil {
|
||||
enc = &Ed25519Encryption{}
|
||||
}*/
|
||||
log.Warn("createEd25519Encryption is not implemented")
|
||||
return
|
||||
}
|
||||
|
||||
@ -60,11 +67,18 @@ type Ed25519Encryption struct {
|
||||
}
|
||||
|
||||
func (ed25519 *Ed25519Encryption) Encrypt(data []byte) (enc []byte, err error) {
|
||||
log.Warn("createEd25519Encryption is not implemented")
|
||||
return ed25519.EncryptPadding(data, true)
|
||||
}
|
||||
|
||||
func (ed25519 *Ed25519Encryption) EncryptPadding(data []byte, zeroPadding bool) (encrypted []byte, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
"zero_padding": zeroPadding,
|
||||
}).Debug("Encrypting data with padding using Ed25519")
|
||||
|
||||
if len(data) > 222 {
|
||||
log.Error("Data too big for Ed25519 encryption")
|
||||
err = Ed25519EncryptTooBig
|
||||
return
|
||||
}
|
||||
@ -87,33 +101,56 @@ func (ed25519 *Ed25519Encryption) EncryptPadding(data []byte, zeroPadding bool)
|
||||
copy(encrypted, ed25519.a.Bytes())
|
||||
copy(encrypted[256:], b)
|
||||
}
|
||||
|
||||
log.WithField("encrypted_length", len(encrypted)).Debug("Data encrypted successfully with Ed25519")
|
||||
return
|
||||
}
|
||||
|
||||
func (elg Ed25519PublicKey) NewEncrypter() (enc Encrypter, err error) {
|
||||
log.Debug("Creating new Ed25519 encrypter")
|
||||
k := createEd25519PublicKey(elg[:])
|
||||
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
|
||||
}
|
||||
|
||||
func (v *Ed25519Verifier) VerifyHash(h, sig []byte) (err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"hash_length": len(h),
|
||||
"sig_length": len(sig),
|
||||
}).Debug("Verifying Ed25519 signature hash")
|
||||
|
||||
if len(sig) != ed25519.SignatureSize {
|
||||
log.Error("Bad Ed25519 signature size")
|
||||
err = ErrBadSignatureSize
|
||||
return
|
||||
}
|
||||
if len(v.k) != ed25519.PublicKeySize {
|
||||
log.Error("Invalid Ed25519 public key size")
|
||||
err = errors.New("failed to verify: invalid ed25519 public key size")
|
||||
return
|
||||
}
|
||||
|
||||
ok := ed25519.Verify(v.k, h, sig)
|
||||
if !ok {
|
||||
log.Warn("Invalid Ed25519 signature")
|
||||
err = errors.New("failed to verify: invalid signature")
|
||||
} else {
|
||||
log.Debug("Ed25519 signature verified successfully")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (v *Ed25519Verifier) Verify(data, sig []byte) (err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
"sig_length": len(sig),
|
||||
}).Debug("Verifying Ed25519 signature")
|
||||
|
||||
h := sha512.Sum512(data)
|
||||
err = v.VerifyHash(h[:], sig)
|
||||
return
|
||||
@ -126,7 +163,10 @@ type Ed25519Signer struct {
|
||||
}
|
||||
|
||||
func (s *Ed25519Signer) Sign(data []byte) (sig []byte, err error) {
|
||||
log.WithField("data_length", len(data)).Debug("Signing data with Ed25519")
|
||||
|
||||
if len(s.k) != ed25519.PrivateKeySize {
|
||||
log.Error("Invalid Ed25519 private key size")
|
||||
err = errors.New("failed to sign: invalid ed25519 private key size")
|
||||
return
|
||||
}
|
||||
@ -136,6 +176,8 @@ func (s *Ed25519Signer) Sign(data []byte) (sig []byte, err error) {
|
||||
}
|
||||
|
||||
func (s *Ed25519Signer) SignHash(h []byte) (sig []byte, err error) {
|
||||
log.WithField("hash_length", len(h)).Debug("Signing hash with Ed25519")
|
||||
sig = ed25519.Sign(s.k, h)
|
||||
log.WithField("signature_length", len(sig)).Debug("Ed25519 signature created successfully")
|
||||
return
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"golang.org/x/crypto/openpgp/elgamal"
|
||||
)
|
||||
|
||||
@ -42,6 +44,7 @@ var (
|
||||
|
||||
// generate an elgamal key pair
|
||||
func ElgamalGenerate(priv *elgamal.PrivateKey, rand io.Reader) (err error) {
|
||||
log.Debug("Generating ElGamal key pair")
|
||||
priv.P = elgp
|
||||
priv.G = elgg
|
||||
xBytes := make([]byte, priv.P.BitLen()/8)
|
||||
@ -51,6 +54,9 @@ func ElgamalGenerate(priv *elgamal.PrivateKey, rand io.Reader) (err error) {
|
||||
priv.X = new(big.Int).SetBytes(xBytes)
|
||||
// compute public key
|
||||
priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P)
|
||||
log.Debug("ElGamal key pair generated successfully")
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to generate ElGamal key pair")
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -60,12 +66,23 @@ type elgDecrypter struct {
|
||||
}
|
||||
|
||||
func (elg *elgDecrypter) Decrypt(data []byte) (dec []byte, err error) {
|
||||
log.WithField("data_length", len(data)).Debug("Decrypting ElGamal data")
|
||||
dec, err = elgamalDecrypt(elg.k, data, true) // TODO(psi): should this be true or false?
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to decrypt ElGamal data")
|
||||
} else {
|
||||
log.WithField("decrypted_length", len(dec)).Debug("ElGamal data decrypted successfully")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// decrypt an elgamal encrypted message, i2p style
|
||||
func elgamalDecrypt(priv *elgamal.PrivateKey, data []byte, zeroPadding bool) (decrypted []byte, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
"zero_padding": zeroPadding,
|
||||
}).Debug("Decrypting ElGamal data")
|
||||
|
||||
a := new(big.Int)
|
||||
b := new(big.Int)
|
||||
idx := 0
|
||||
@ -87,9 +104,11 @@ func elgamalDecrypt(priv *elgamal.PrivateKey, data []byte, zeroPadding bool) (de
|
||||
if subtle.ConstantTimeCompare(d[:], m[1:33]) == 1 {
|
||||
// decryption successful
|
||||
good = 1
|
||||
log.Debug("ElGamal decryption successful")
|
||||
} else {
|
||||
// decrypt failed
|
||||
err = ElgDecryptFail
|
||||
log.WithError(err).Error("ElGamal decryption failed")
|
||||
}
|
||||
// copy result
|
||||
decrypted = make([]byte, 222)
|
||||
@ -107,10 +126,16 @@ type ElgamalEncryption struct {
|
||||
}
|
||||
|
||||
func (elg *ElgamalEncryption) Encrypt(data []byte) (enc []byte, err error) {
|
||||
log.WithField("data_length", len(data)).Debug("Encrypting data with ElGamal")
|
||||
return elg.EncryptPadding(data, true)
|
||||
}
|
||||
|
||||
func (elg *ElgamalEncryption) EncryptPadding(data []byte, zeroPadding bool) (encrypted []byte, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
"zero_padding": zeroPadding,
|
||||
}).Debug("Encrypting data with ElGamal padding")
|
||||
|
||||
if len(data) > 222 {
|
||||
err = ElgEncryptTooBig
|
||||
return
|
||||
@ -134,23 +159,31 @@ func (elg *ElgamalEncryption) EncryptPadding(data []byte, zeroPadding bool) (enc
|
||||
copy(encrypted, elg.a.Bytes())
|
||||
copy(encrypted[256:], b)
|
||||
}
|
||||
|
||||
log.WithField("encrypted_length", len(encrypted)).Debug("Data encrypted successfully with ElGamal")
|
||||
return
|
||||
}
|
||||
|
||||
// create an elgamal public key from byte slice
|
||||
func createElgamalPublicKey(data []byte) (k *elgamal.PublicKey) {
|
||||
log.WithField("data_length", len(data)).Debug("Creating ElGamal public key")
|
||||
if len(data) == 256 {
|
||||
k = &elgamal.PublicKey{
|
||||
G: elgg,
|
||||
P: elgp,
|
||||
Y: new(big.Int).SetBytes(data),
|
||||
}
|
||||
log.Debug("ElGamal public key created successfully")
|
||||
} else {
|
||||
log.Warn("Invalid data length for ElGamal public key")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// create an elgamal private key from byte slice
|
||||
func createElgamalPrivateKey(data []byte) (k *elgamal.PrivateKey) {
|
||||
log.WithField("data_length", len(data)).Debug("Creating ElGamal private key")
|
||||
if len(data) == 256 {
|
||||
x := new(big.Int).SetBytes(data)
|
||||
y := new(big.Int).Exp(elgg, x, elgp)
|
||||
@ -162,12 +195,16 @@ func createElgamalPrivateKey(data []byte) (k *elgamal.PrivateKey) {
|
||||
},
|
||||
X: x,
|
||||
}
|
||||
log.Debug("ElGamal private key created successfully")
|
||||
} else {
|
||||
log.Warn("Invalid data length for ElGamal private key")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// create a new elgamal encryption session
|
||||
func createElgamalEncryption(pub *elgamal.PublicKey, rand io.Reader) (enc *ElgamalEncryption, err error) {
|
||||
log.Debug("Creating ElGamal encryption session")
|
||||
kbytes := make([]byte, 256)
|
||||
k := new(big.Int)
|
||||
for err == nil {
|
||||
@ -184,6 +221,9 @@ func createElgamalEncryption(pub *elgamal.PublicKey, rand io.Reader) (enc *Elgam
|
||||
a: new(big.Int).Exp(pub.G, k, pub.P),
|
||||
b1: new(big.Int).Exp(pub.Y, k, pub.P),
|
||||
}
|
||||
log.Debug("ElGamal encryption session created successfully")
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to create ElGamal encryption session")
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -198,8 +238,14 @@ func (elg ElgPublicKey) Len() int {
|
||||
}
|
||||
|
||||
func (elg ElgPublicKey) NewEncrypter() (enc Encrypter, err error) {
|
||||
log.Debug("Creating new ElGamal encrypter")
|
||||
k := createElgamalPublicKey(elg[:])
|
||||
enc, err = createElgamalEncryption(k, rand.Reader)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create ElGamal encrypter")
|
||||
} else {
|
||||
log.Debug("ElGamal encrypter created successfully")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -208,8 +254,10 @@ func (elg ElgPrivateKey) Len() int {
|
||||
}
|
||||
|
||||
func (elg ElgPrivateKey) NewDecrypter() (dec Decrypter, err error) {
|
||||
log.Debug("Creating new ElGamal decrypter")
|
||||
dec = &elgDecrypter{
|
||||
k: createElgamalPrivateKey(elg[:]),
|
||||
}
|
||||
log.Debug("ElGamal decrypter created successfully")
|
||||
return
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/openpgp/elgamal"
|
||||
)
|
||||
|
||||
@ -46,7 +45,7 @@ func BenchmarkElgDecrypt(b *testing.B) {
|
||||
fails++
|
||||
}
|
||||
}
|
||||
log.Infof("%d fails %d rounds", fails, b.N)
|
||||
log.Debugf("%d fails %d rounds", fails, b.N)
|
||||
}
|
||||
|
||||
func BenchmarkElgEncrypt(b *testing.B) {
|
||||
@ -69,7 +68,7 @@ func BenchmarkElgEncrypt(b *testing.B) {
|
||||
fails++
|
||||
}
|
||||
}
|
||||
log.Infof("%d fails %d rounds", fails, b.N)
|
||||
log.Debugf("%d fails %d rounds", fails, b.N)
|
||||
}
|
||||
|
||||
func TestElg(t *testing.T) {
|
||||
|
@ -19,6 +19,7 @@ type Tunnel struct {
|
||||
}
|
||||
|
||||
func NewTunnelCrypto(layerKey, ivKey TunnelKey) (t *Tunnel, err error) {
|
||||
log.Debug("Creating new Tunnel crypto")
|
||||
t = new(Tunnel)
|
||||
t.layerKey, err = aes.NewCipher(layerKey[:])
|
||||
if err == nil {
|
||||
@ -27,24 +28,31 @@ func NewTunnelCrypto(layerKey, ivKey TunnelKey) (t *Tunnel, err error) {
|
||||
|
||||
if err != nil {
|
||||
// error happened we don't need t
|
||||
// log.WithError(err).Error("Failed to create Tunnel crypto")
|
||||
t = nil
|
||||
} else {
|
||||
log.Debug("Tunnel crypto created successfully")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// encrypt tunnel data in place
|
||||
func (t *Tunnel) Encrypt(td *TunnelData) {
|
||||
log.Debug("Encrypting Tunnel data")
|
||||
data := *td
|
||||
t.ivKey.Encrypt(data[16:1024], data[16:1024])
|
||||
layerBlock := cipher.NewCBCEncrypter(t.layerKey, data[:16])
|
||||
layerBlock.CryptBlocks(data[16:1024], data[16:1024])
|
||||
t.ivKey.Encrypt(data[16:1024], data[16:1024])
|
||||
log.Debug("Tunnel data encrypted successfully")
|
||||
}
|
||||
|
||||
func (t *Tunnel) Decrypt(td *TunnelData) {
|
||||
log.Debug("Decrypting Tunnel data")
|
||||
data := *td
|
||||
t.ivKey.Decrypt(data[16:1024], data[16:1024])
|
||||
layerBlock := cipher.NewCBCDecrypter(t.layerKey, data[:16])
|
||||
layerBlock.CryptBlocks(data[16:1024], data[16:1024])
|
||||
t.ivKey.Decrypt(data[16:1024], data[16:1024])
|
||||
log.Debug("Tunnel data decrypted successfully")
|
||||
}
|
||||
|
@ -4,12 +4,16 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
common "github.com/go-i2p/go-i2p/lib/common/data"
|
||||
"github.com/go-i2p/go-i2p/lib/common/session_key"
|
||||
"github.com/go-i2p/go-i2p/lib/tunnel"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
/*
|
||||
I2P I2NP BuildRequestRecord
|
||||
https://geti2p.net/spec/i2np
|
||||
@ -172,80 +176,94 @@ type BuildRequestRecord struct {
|
||||
var ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA = errors.New("not enough i2np build request record data")
|
||||
|
||||
func ReadBuildRequestRecord(data []byte) (BuildRequestRecord, error) {
|
||||
log.Debug("Reading BuildRequestRecord")
|
||||
build_request_record := BuildRequestRecord{}
|
||||
|
||||
receive_tunnel, err := readBuildRequestRecordReceiveTunnel(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read ReceiveTunnel")
|
||||
return build_request_record, err
|
||||
}
|
||||
build_request_record.ReceiveTunnel = receive_tunnel
|
||||
|
||||
our_ident, err := readBuildRequestRecordOurIdent(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read OurIdent")
|
||||
return build_request_record, err
|
||||
}
|
||||
build_request_record.OurIdent = our_ident
|
||||
|
||||
next_tunnel, err := readBuildRequestRecordNextTunnel(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read NextTunnel")
|
||||
return build_request_record, err
|
||||
}
|
||||
build_request_record.NextTunnel = next_tunnel
|
||||
|
||||
next_ident, err := readBuildRequestRecordNextIdent(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read NextIdent")
|
||||
return build_request_record, err
|
||||
}
|
||||
build_request_record.NextIdent = next_ident
|
||||
|
||||
layer_key, err := readBuildRequestRecordLayerKey(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read LayerKey")
|
||||
return build_request_record, err
|
||||
}
|
||||
build_request_record.LayerKey = layer_key
|
||||
|
||||
iv_key, err := readBuildRequestRecordIVKey(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read IVKey")
|
||||
return build_request_record, err
|
||||
}
|
||||
build_request_record.IVKey = iv_key
|
||||
|
||||
reply_key, err := readBuildRequestRecordReplyKey(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read ReplyKey")
|
||||
return build_request_record, err
|
||||
}
|
||||
build_request_record.ReplyKey = reply_key
|
||||
|
||||
reply_iv, err := readBuildRequestRecordReplyIV(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read ReplyIV")
|
||||
return build_request_record, err
|
||||
}
|
||||
build_request_record.ReplyIV = reply_iv
|
||||
|
||||
flag, err := readBuildRequestRecordFlag(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read Flag")
|
||||
return build_request_record, err
|
||||
}
|
||||
build_request_record.Flag = flag
|
||||
|
||||
request_time, err := readBuildRequestRecordRequestTime(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read RequestTime")
|
||||
return build_request_record, err
|
||||
}
|
||||
build_request_record.RequestTime = request_time
|
||||
|
||||
send_message_id, err := readBuildRequestRecordSendMessageID(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read SendMessageID")
|
||||
return build_request_record, err
|
||||
}
|
||||
build_request_record.SendMessageID = send_message_id
|
||||
|
||||
padding, err := readBuildRequestRecordPadding(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read Padding")
|
||||
return build_request_record, err
|
||||
}
|
||||
build_request_record.Padding = padding
|
||||
|
||||
log.Debug("BuildRequestRecord read successfully")
|
||||
return build_request_record, nil
|
||||
}
|
||||
|
||||
@ -258,7 +276,7 @@ func readBuildRequestRecordReceiveTunnel(data []byte) (tunnel.TunnelID, error) {
|
||||
common.Integer(data[0:4]).Int(),
|
||||
)
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.readBuildRequestRecordReceiveTunnel",
|
||||
"receieve_tunnel": receive_tunnel,
|
||||
}).Debug("parsed_build_request_record_receive_tunnel")
|
||||
@ -273,7 +291,7 @@ func readBuildRequestRecordOurIdent(data []byte) (common.Hash, error) {
|
||||
hash := common.Hash{}
|
||||
copy(hash[:], data[4:36])
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.readBuildRequestRecordOurIdent",
|
||||
}).Debug("parsed_build_request_record_our_ident")
|
||||
return hash, nil
|
||||
@ -288,7 +306,7 @@ func readBuildRequestRecordNextTunnel(data []byte) (tunnel.TunnelID, error) {
|
||||
common.Integer(data[36:40]).Int(),
|
||||
)
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.readBuildRequestRecordNextTunnel",
|
||||
"next_tunnel": next_tunnel,
|
||||
}).Debug("parsed_build_request_record_next_tunnel")
|
||||
@ -303,7 +321,7 @@ func readBuildRequestRecordNextIdent(data []byte) (common.Hash, error) {
|
||||
hash := common.Hash{}
|
||||
copy(hash[:], data[40:72])
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.readBuildRequestRecordNextIdent",
|
||||
}).Debug("parsed_build_request_record_next_ident")
|
||||
return hash, nil
|
||||
@ -317,7 +335,7 @@ func readBuildRequestRecordLayerKey(data []byte) (session_key.SessionKey, error)
|
||||
session_key := session_key.SessionKey{}
|
||||
copy(session_key[:], data[72:104])
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.readBuildRequestRecordLayerKey",
|
||||
}).Debug("parsed_build_request_record_layer_key")
|
||||
return session_key, nil
|
||||
@ -331,7 +349,7 @@ func readBuildRequestRecordIVKey(data []byte) (session_key.SessionKey, error) {
|
||||
session_key := session_key.SessionKey{}
|
||||
copy(session_key[:], data[104:136])
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.readBuildRequestRecordIVKey",
|
||||
}).Debug("parsed_build_request_record_iv_key")
|
||||
return session_key, nil
|
||||
@ -345,7 +363,7 @@ func readBuildRequestRecordReplyKey(data []byte) (session_key.SessionKey, error)
|
||||
session_key := session_key.SessionKey{}
|
||||
copy(session_key[:], data[136:168])
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.readBuildRequestRecordReplyKey",
|
||||
}).Debug("parsed_build_request_record_reply_key")
|
||||
return session_key, nil
|
||||
@ -359,7 +377,7 @@ func readBuildRequestRecordReplyIV(data []byte) ([16]byte, error) {
|
||||
iv := [16]byte{}
|
||||
copy(iv[:], data[168:184])
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.readBuildRequestRecordReplyIV",
|
||||
}).Debug("parsed_build_request_record_reply_iv")
|
||||
return iv, nil
|
||||
@ -372,7 +390,7 @@ func readBuildRequestRecordFlag(data []byte) (int, error) {
|
||||
|
||||
flag := common.Integer([]byte{data[185]}).Int()
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.readBuildRequestRecordFlag",
|
||||
"flag": flag,
|
||||
}).Debug("parsed_build_request_record_flag")
|
||||
@ -387,7 +405,7 @@ func readBuildRequestRecordRequestTime(data []byte) (time.Time, error) {
|
||||
count := common.Integer(data[185:189]).Int()
|
||||
rtime := time.Unix(0, 0).Add(time.Duration(count) * time.Hour)
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.readBuildRequestRecordRequestTime",
|
||||
}).Debug("parsed_build_request_record_request_time")
|
||||
return rtime, nil
|
||||
@ -400,7 +418,7 @@ func readBuildRequestRecordSendMessageID(data []byte) (int, error) {
|
||||
|
||||
send_message_id := common.Integer(data[189:193]).Int()
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.readBuildRequestRecordSendMessageID",
|
||||
}).Debug("parsed_build_request_record_send_message_id")
|
||||
return send_message_id, nil
|
||||
@ -414,7 +432,7 @@ func readBuildRequestRecordPadding(data []byte) ([29]byte, error) {
|
||||
padding := [29]byte{}
|
||||
copy(padding[:], data[193:222])
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.readBuildRequestRecordPadding",
|
||||
}).Debug("parsed_build_request_record_padding")
|
||||
return padding, nil
|
||||
|
@ -4,9 +4,9 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
datalib "github.com/go-i2p/go-i2p/lib/common/data"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
datalib "github.com/go-i2p/go-i2p/lib/common/data"
|
||||
)
|
||||
|
||||
/*
|
||||
@ -95,10 +95,12 @@ var ERR_I2NP_NOT_ENOUGH_DATA = errors.New("not enough i2np header data")
|
||||
// Read an entire I2NP message and return the parsed header
|
||||
// with embedded encrypted data
|
||||
func ReadI2NPNTCPHeader(data []byte) (I2NPNTCPHeader, error) {
|
||||
log.Debug("Reading I2NP NTCP Header")
|
||||
header := I2NPNTCPHeader{}
|
||||
|
||||
message_type, err := ReadI2NPType(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read I2NP type")
|
||||
return header, err
|
||||
} else {
|
||||
header.Type = message_type
|
||||
@ -106,6 +108,7 @@ func ReadI2NPNTCPHeader(data []byte) (I2NPNTCPHeader, error) {
|
||||
|
||||
message_id, err := ReadI2NPNTCPMessageID(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read I2NP NTCP message ID")
|
||||
return header, err
|
||||
} else {
|
||||
header.MessageID = message_id
|
||||
@ -113,6 +116,7 @@ func ReadI2NPNTCPHeader(data []byte) (I2NPNTCPHeader, error) {
|
||||
|
||||
message_date, err := ReadI2NPNTCPMessageExpiration(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read I2NP NTCP message expiration")
|
||||
return header, err
|
||||
} else {
|
||||
header.Expiration = message_date.Time()
|
||||
@ -120,6 +124,7 @@ func ReadI2NPNTCPHeader(data []byte) (I2NPNTCPHeader, error) {
|
||||
|
||||
message_size, err := ReadI2NPNTCPMessageSize(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read I2NP NTCP message size")
|
||||
return header, err
|
||||
} else {
|
||||
header.Size = message_size
|
||||
@ -127,6 +132,7 @@ func ReadI2NPNTCPHeader(data []byte) (I2NPNTCPHeader, error) {
|
||||
|
||||
message_checksum, err := ReadI2NPNTCPMessageChecksum(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read I2NP NTCP message checksum")
|
||||
return header, err
|
||||
} else {
|
||||
header.Checksum = message_checksum
|
||||
@ -134,12 +140,13 @@ func ReadI2NPNTCPHeader(data []byte) (I2NPNTCPHeader, error) {
|
||||
|
||||
message_data, err := ReadI2NPNTCPData(data, header.Size)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read I2NP NTCP message data")
|
||||
return header, err
|
||||
} else {
|
||||
header.Data = message_data
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.ReadI2NPNTCPHeader",
|
||||
}).Debug("parsed_i2np_ntcp_header")
|
||||
return header, nil
|
||||
@ -150,6 +157,7 @@ func ReadI2NPSSUHeader(data []byte) (I2NPSSUHeader, error) {
|
||||
|
||||
message_type, err := ReadI2NPType(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read I2NP type")
|
||||
return header, err
|
||||
} else {
|
||||
header.Type = message_type
|
||||
@ -157,11 +165,14 @@ func ReadI2NPSSUHeader(data []byte) (I2NPSSUHeader, error) {
|
||||
|
||||
message_date, err := ReadI2NPSSUMessageExpiration(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read I2NP SSU message expiration")
|
||||
return header, err
|
||||
} else {
|
||||
header.Expiration = message_date.Time()
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"type": header.Type,
|
||||
}).Debug("Parsed I2NP SSU header")
|
||||
return header, nil
|
||||
}
|
||||
|
||||
@ -174,27 +185,27 @@ func ReadI2NPType(data []byte) (int, error) {
|
||||
|
||||
if (message_type.Int() >= 4 || message_type.Int() <= 9) ||
|
||||
(message_type.Int() >= 12 || message_type.Int() <= 17) {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.ReadI2NPType",
|
||||
"type": message_type,
|
||||
}).Warn("unknown_i2np_type")
|
||||
}
|
||||
|
||||
if message_type.Int() >= 224 || message_type.Int() <= 254 {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.ReadI2NPType",
|
||||
"type": message_type,
|
||||
}).Warn("experimental_i2np_type")
|
||||
}
|
||||
|
||||
if message_type.Int() == 255 {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.ReadI2NPType",
|
||||
"type": message_type,
|
||||
}).Warn("reserved_i2np_type")
|
||||
}
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.ReadI2NPType",
|
||||
"type": message_type,
|
||||
}).Debug("parsed_i2np_type")
|
||||
@ -208,7 +219,7 @@ func ReadI2NPNTCPMessageID(data []byte) (int, error) {
|
||||
|
||||
message_id := datalib.Integer(data[1:5])
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.ReadI2NPNTCPMessageID",
|
||||
"type": message_id,
|
||||
}).Debug("parsed_i2np_message_id")
|
||||
@ -223,7 +234,7 @@ func ReadI2NPNTCPMessageExpiration(data []byte) (datalib.Date, error) {
|
||||
date := datalib.Date{}
|
||||
copy(date[:], data[5:13])
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.ReadI2NPNTCPMessageExpiration",
|
||||
"date": date,
|
||||
}).Debug("parsed_i2np_message_date")
|
||||
@ -238,7 +249,7 @@ func ReadI2NPSSUMessageExpiration(data []byte) (datalib.Date, error) {
|
||||
date := datalib.Date{}
|
||||
copy(date[4:], data[1:5])
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.ReadI2NPSSUMessageExpiration",
|
||||
"date": date,
|
||||
}).Debug("parsed_i2np_message_date")
|
||||
@ -252,7 +263,7 @@ func ReadI2NPNTCPMessageSize(data []byte) (int, error) {
|
||||
|
||||
size := datalib.Integer(data[13:15])
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.ReadI2NPNTCPMessageSize",
|
||||
"size": size,
|
||||
}).Debug("parsed_i2np_message_size")
|
||||
@ -266,7 +277,7 @@ func ReadI2NPNTCPMessageChecksum(data []byte) (int, error) {
|
||||
|
||||
checksum := datalib.Integer(data[15:16])
|
||||
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "i2np.ReadI2NPNTCPMessageCHecksum",
|
||||
"checksum": checksum,
|
||||
}).Debug("parsed_i2np_message_checksum")
|
||||
@ -277,6 +288,6 @@ func ReadI2NPNTCPData(data []byte, size int) ([]byte, error) {
|
||||
if len(data) < 16+size {
|
||||
return []byte{}, ERR_I2NP_NOT_ENOUGH_DATA
|
||||
}
|
||||
|
||||
log.WithField("data_size", size).Debug("Read I2NP NTCP message data")
|
||||
return data[16 : 16+size], nil
|
||||
}
|
||||
|
@ -3,19 +3,23 @@ package reseed
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/eyedeekay/go-unzip/pkg/unzip"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
"github.com/go-i2p/go-i2p/lib/config"
|
||||
"github.com/go-i2p/go-i2p/lib/su3"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
const (
|
||||
I2pUserAgent = "Wget/1.11.4"
|
||||
)
|
||||
@ -25,6 +29,8 @@ type Reseed struct {
|
||||
}
|
||||
|
||||
func (r Reseed) SingleReseed(uri string) ([]router_info.RouterInfo, error) {
|
||||
log.WithField("uri", uri).Debug("Starting single reseed operation")
|
||||
|
||||
transport := http.Transport{
|
||||
DialContext: r.DialContext,
|
||||
}
|
||||
@ -33,6 +39,7 @@ func (r Reseed) SingleReseed(uri string) ([]router_info.RouterInfo, error) {
|
||||
}
|
||||
URL, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to parse reseed URI")
|
||||
return nil, err
|
||||
}
|
||||
header := http.Header{}
|
||||
@ -43,12 +50,23 @@ func (r Reseed) SingleReseed(uri string) ([]router_info.RouterInfo, error) {
|
||||
}
|
||||
response, err := client.Do(&request)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to perform HTTP request")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug("Successfully received response from reseed server")
|
||||
|
||||
su3file, err := su3.Read(response.Body)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read SU3 file")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"file_type": su3file.FileType,
|
||||
"content_type": su3file.ContentType,
|
||||
}).Debug("Successfully read SU3 file")
|
||||
|
||||
if su3file.FileType == su3.ZIP {
|
||||
if su3file.ContentType == su3.RESEED {
|
||||
if err == nil {
|
||||
@ -59,36 +77,53 @@ func (r Reseed) SingleReseed(uri string) ([]router_info.RouterInfo, error) {
|
||||
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)
|
||||
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
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to read SU3 file signature")
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Error("Undefined reseed error")
|
||||
return nil, fmt.Errorf("error: undefined reseed error")
|
||||
}
|
||||
|
@ -10,15 +10,19 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/bootstrap"
|
||||
"github.com/go-i2p/go-i2p/lib/common/base32"
|
||||
"github.com/go-i2p/go-i2p/lib/common/base64"
|
||||
common "github.com/go-i2p/go-i2p/lib/common/data"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
"github.com/go-i2p/go-i2p/lib/util"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
// standard network database implementation using local filesystem skiplist
|
||||
type StdNetDB struct {
|
||||
DB string
|
||||
@ -27,6 +31,7 @@ type StdNetDB struct {
|
||||
}
|
||||
|
||||
func NewStdNetDB(db string) StdNetDB {
|
||||
log.WithField("db_path", db).Debug("Creating new StdNetDB")
|
||||
return StdNetDB{
|
||||
DB: db,
|
||||
RouterInfos: make(map[common.Hash]Entry),
|
||||
@ -35,16 +40,20 @@ func NewStdNetDB(db string) StdNetDB {
|
||||
}
|
||||
|
||||
func (db *StdNetDB) GetRouterInfo(hash common.Hash) (chnl chan router_info.RouterInfo) {
|
||||
log.WithField("hash", hash).Debug("Getting RouterInfo")
|
||||
if ri, ok := db.RouterInfos[hash]; ok {
|
||||
log.Debug("RouterInfo found in memory cache")
|
||||
chnl <- *ri.RouterInfo
|
||||
return
|
||||
}
|
||||
fname := db.SkiplistFile(hash)
|
||||
buff := new(bytes.Buffer)
|
||||
if f, err := os.Open(fname); err != nil {
|
||||
log.WithError(err).Error("Failed to open RouterInfo file")
|
||||
return nil
|
||||
} else {
|
||||
if _, err := io.Copy(buff, f); err != nil {
|
||||
log.WithError(err).Error("Failed to read RouterInfo file")
|
||||
return nil
|
||||
}
|
||||
defer f.Close()
|
||||
@ -53,11 +62,14 @@ func (db *StdNetDB) GetRouterInfo(hash common.Hash) (chnl chan router_info.Route
|
||||
ri, _, err := router_info.ReadRouterInfo(buff.Bytes())
|
||||
if err == nil {
|
||||
if _, ok := db.RouterInfos[hash]; !ok {
|
||||
log.Debug("Adding RouterInfo to memory cache")
|
||||
db.RouterInfos[hash] = Entry{
|
||||
RouterInfo: &ri,
|
||||
}
|
||||
}
|
||||
chnl <- ri
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to parse RouterInfo")
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -66,6 +78,7 @@ func (db *StdNetDB) GetRouterInfo(hash common.Hash) (chnl chan router_info.Route
|
||||
func (db *StdNetDB) SkiplistFile(hash common.Hash) (fpath string) {
|
||||
fname := base64.EncodeToString(hash[:])
|
||||
fpath = filepath.Join(db.Path(), fmt.Sprintf("r%c", fname[0]), fmt.Sprintf("routerInfo-%s.dat", fname))
|
||||
log.WithField("file_path", fpath).Debug("Generated skiplist file path")
|
||||
return
|
||||
}
|
||||
|
||||
@ -77,19 +90,27 @@ func (db *StdNetDB) Path() string {
|
||||
// return how many routers we know about in our network database
|
||||
func (db *StdNetDB) Size() (routers int) {
|
||||
// TODO: implement this
|
||||
log.Debug("Calculating NetDB size")
|
||||
var err error
|
||||
var data []byte
|
||||
if !util.CheckFileExists(db.cacheFilePath()) || util.CheckFileAge(db.cacheFilePath(), 2) || len(db.RouterInfos) == 0 {
|
||||
// regenerate
|
||||
log.Debug("Recalculating NetDB size")
|
||||
err = db.RecalculateSize()
|
||||
if err != nil {
|
||||
// TODO : what now? let's panic for now
|
||||
util.Panicf("could not recalculate netdb size: %s", err)
|
||||
// util.Panicf("could not recalculate netdb size: %s", err)
|
||||
log.WithError(err).Panic("Failed to recalculate NetDB size")
|
||||
}
|
||||
}
|
||||
data, err = ioutil.ReadFile(db.cacheFilePath())
|
||||
if err == nil {
|
||||
routers, err = strconv.Atoi(string(data))
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to parse NetDB size from cache")
|
||||
}
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to read NetDB size cache file")
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -104,61 +125,83 @@ func (db *StdNetDB) cacheFilePath() string {
|
||||
|
||||
func (db *StdNetDB) CheckFilePathValid(fpath string) bool {
|
||||
// TODO: make this better
|
||||
return strings.HasSuffix(fpath, ".dat")
|
||||
// return strings.HasSuffix(fpath, ".dat")
|
||||
isValid := strings.HasSuffix(fpath, ".dat")
|
||||
log.WithFields(logrus.Fields{
|
||||
"file_path": fpath,
|
||||
"is_valid": isValid,
|
||||
}).Debug("Checking file path validity")
|
||||
return isValid
|
||||
}
|
||||
|
||||
// recalculateSize recalculates cached size of netdb
|
||||
func (db *StdNetDB) RecalculateSize() (err error) {
|
||||
log.Debug("Recalculating NetDB size")
|
||||
count := 0
|
||||
err = filepath.Walk(db.Path(), func(fname string, info os.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
if !strings.HasPrefix(fname, db.Path()) {
|
||||
if db.Path() == fname {
|
||||
log.Info("path==name time to exit")
|
||||
log.Debug("Reached end of NetDB directory")
|
||||
log.Debug("path==name time to exit")
|
||||
return nil
|
||||
}
|
||||
log.Info("Outside of netDb dir time to exit", db.Path(), " ", fname)
|
||||
log.Debug("Outside of netDb dir time to exit", db.Path(), " ", fname)
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
if db.CheckFilePathValid(fname) {
|
||||
log.WithField("file_name", fname).Debug("Reading RouterInfo file")
|
||||
log.Println("Reading in file:", fname)
|
||||
b, err := os.ReadFile(fname)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read RouterInfo file")
|
||||
return err
|
||||
}
|
||||
ri, _, err := router_info.ReadRouterInfo(b)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to parse RouterInfo")
|
||||
return err
|
||||
}
|
||||
ih := ri.IdentHash().Bytes()
|
||||
log.WithError(err).Error("Failed to parse RouterInfo")
|
||||
log.Printf("Read in IdentHash: %s", base32.EncodeToString(ih[:]))
|
||||
for _, addr := range ri.RouterAddresses() {
|
||||
log.Println(string(addr.Bytes()))
|
||||
log.WithField("address", string(addr.Bytes())).Debug("RouterInfo address")
|
||||
}
|
||||
if ent, ok := db.RouterInfos[ih]; !ok {
|
||||
log.Debug("Adding new RouterInfo to memory cache")
|
||||
db.RouterInfos[ri.IdentHash()] = Entry{
|
||||
RouterInfo: &ri,
|
||||
}
|
||||
} else {
|
||||
log.Debug("RouterInfo already in memory cache")
|
||||
log.Println("entry previously found in table", ent, fname)
|
||||
}
|
||||
ri = router_info.RouterInfo{}
|
||||
count++
|
||||
} else {
|
||||
log.WithField("file_path", fname).Warn("Invalid file path")
|
||||
log.Println("Invalid path error")
|
||||
}
|
||||
return err
|
||||
})
|
||||
if err == nil {
|
||||
log.WithField("count", count).Debug("Finished recalculating NetDB size")
|
||||
str := fmt.Sprintf("%d", count)
|
||||
var f *os.File
|
||||
f, err = os.OpenFile(db.cacheFilePath(), os.O_CREATE|os.O_WRONLY, 0o600)
|
||||
if err == nil {
|
||||
_, err = io.WriteString(f, str)
|
||||
f.Close()
|
||||
log.Debug("Updated NetDB size cache file")
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to update NetDB size cache file")
|
||||
}
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to update NetDB size cache file")
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -182,24 +225,35 @@ func (db *StdNetDB) Exists() bool {
|
||||
func (db *StdNetDB) SaveEntry(e *Entry) (err error) {
|
||||
var f io.WriteCloser
|
||||
h := e.RouterInfo.IdentHash()
|
||||
log.WithField("hash", h).Debug("Saving NetDB entry")
|
||||
// if err == nil {
|
||||
f, err = os.OpenFile(db.SkiplistFile(h), os.O_WRONLY|os.O_CREATE, 0o700)
|
||||
if err == nil {
|
||||
err = e.WriteTo(f)
|
||||
f.Close()
|
||||
if err == nil {
|
||||
log.Debug("Successfully saved NetDB entry")
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to write NetDB entry")
|
||||
}
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to open file for saving NetDB entry")
|
||||
}
|
||||
//}
|
||||
if err != nil {
|
||||
log.Errorf("failed to save netdb entry: %s", err.Error())
|
||||
}
|
||||
/*
|
||||
if err != nil {
|
||||
log.Errorf("failed to save netdb entry: %s", err.Error())
|
||||
}
|
||||
*/
|
||||
return
|
||||
}
|
||||
|
||||
func (db *StdNetDB) Save() (err error) {
|
||||
log.Debug("Saving all NetDB entries")
|
||||
for _, dbe := range db.RouterInfos {
|
||||
if e := db.SaveEntry(&dbe); e != nil {
|
||||
err = e
|
||||
// TODO: log this
|
||||
log.WithError(e).Error("Failed to save NetDB entry")
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -208,16 +262,22 @@ func (db *StdNetDB) Save() (err error) {
|
||||
// reseed if we have less than minRouters known routers
|
||||
// returns error if reseed failed
|
||||
func (db *StdNetDB) Reseed(b bootstrap.Bootstrap, minRouters int) (err error) {
|
||||
log.WithField("min_routers", minRouters).Debug("Checking if reseed is necessary")
|
||||
if db.Size() > minRouters {
|
||||
log.Debug("Reseed not necessary")
|
||||
return nil
|
||||
}
|
||||
log.Warn("NetDB size below minimum, reseed required")
|
||||
return
|
||||
}
|
||||
|
||||
// ensure that the network database exists
|
||||
func (db *StdNetDB) Ensure() (err error) {
|
||||
if !db.Exists() {
|
||||
log.Debug("NetDB directory does not exist, creating it")
|
||||
err = db.Create()
|
||||
} else {
|
||||
log.Debug("NetDB directory already exists")
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -226,18 +286,20 @@ func (db *StdNetDB) Ensure() (err error) {
|
||||
func (db *StdNetDB) Create() (err error) {
|
||||
mode := os.FileMode(0o700)
|
||||
p := db.Path()
|
||||
log.Infof("Create network database in %s", p)
|
||||
|
||||
log.WithField("path", p).Debug("Creating network database directory")
|
||||
// create root for skiplist
|
||||
err = os.Mkdir(p, mode)
|
||||
err = os.MkdirAll(p, mode)
|
||||
if err == nil {
|
||||
// create all subdirectories for skiplist
|
||||
for _, c := range base64.I2PEncodeAlphabet {
|
||||
err = os.Mkdir(filepath.Join(p, fmt.Sprintf("r%c", c)), mode)
|
||||
err = os.MkdirAll(filepath.Join(p, fmt.Sprintf("r%c", c)), mode)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create subdirectory")
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to create root network database directory")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -3,11 +3,15 @@ package router
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/config"
|
||||
"github.com/go-i2p/go-i2p/lib/netdb"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
// i2p router type
|
||||
type Router struct {
|
||||
cfg *config.RouterConfig
|
||||
@ -16,75 +20,94 @@ type Router struct {
|
||||
running bool
|
||||
}
|
||||
|
||||
// create router with default configuration
|
||||
func CreateRouter() (r *Router, err error) {
|
||||
cfg := config.RouterConfigProperties
|
||||
r, err = FromConfig(cfg)
|
||||
return
|
||||
// CreateRouter creates a router with the provided configuration
|
||||
func CreateRouter(cfg *config.RouterConfig) (*Router, error) {
|
||||
log.Debug("Creating router with provided configuration")
|
||||
r, err := FromConfig(cfg)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create router from configuration")
|
||||
} else {
|
||||
log.Debug("Router created successfully with provided configuration")
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
// create router from configuration
|
||||
func FromConfig(c *config.RouterConfig) (r *Router, err error) {
|
||||
log.WithField("config", c).Debug("Creating router from configuration")
|
||||
r = new(Router)
|
||||
r.cfg = c
|
||||
r.closeChnl = make(chan bool)
|
||||
log.Debug("Router created successfully from configuration")
|
||||
return
|
||||
}
|
||||
|
||||
// Wait blocks until router is fully stopped
|
||||
func (r *Router) Wait() {
|
||||
log.Debug("Waiting for router to stop")
|
||||
<-r.closeChnl
|
||||
log.Debug("Router has stopped")
|
||||
}
|
||||
|
||||
// Stop starts stopping internal state of router
|
||||
func (r *Router) Stop() {
|
||||
log.Debug("Stopping router")
|
||||
r.closeChnl <- true
|
||||
r.running = false
|
||||
log.Debug("Router stop signal sent")
|
||||
}
|
||||
|
||||
// Close closes any internal state and finallizes router resources so that nothing can start up again
|
||||
func (r *Router) Close() error {
|
||||
log.Warn("Closing router not implemented(?)")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start starts router mainloop
|
||||
func (r *Router) Start() {
|
||||
if r.running {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Router) Start",
|
||||
"reason": "router is already running",
|
||||
}).Error("Error Starting router")
|
||||
return
|
||||
}
|
||||
log.Debug("Starting router")
|
||||
r.running = true
|
||||
go r.mainloop()
|
||||
}
|
||||
|
||||
// run i2p router mainloop
|
||||
func (r *Router) mainloop() {
|
||||
log.Debug("Entering router mainloop")
|
||||
r.ndb = netdb.NewStdNetDB(r.cfg.NetDb.Path)
|
||||
log.WithField("netdb_path", r.cfg.NetDb.Path).Debug("Created StdNetDB")
|
||||
// make sure the netdb is ready
|
||||
var e error
|
||||
if err := r.ndb.Ensure(); err != nil {
|
||||
e = err
|
||||
log.WithError(err).Error("Failed to ensure NetDB")
|
||||
}
|
||||
if sz := r.ndb.Size(); sz >= 0 {
|
||||
log.Info("NetDB Size:", sz)
|
||||
log.WithField("size", sz).Debug("NetDB Size")
|
||||
} else {
|
||||
log.Warn("Unable to determine NetDB size")
|
||||
}
|
||||
if e == nil {
|
||||
// netdb ready
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Router) mainloop",
|
||||
}).Info("Router ready")
|
||||
}).Debug("Router ready")
|
||||
for e == nil {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
} else {
|
||||
// netdb failed
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Router) mainloop",
|
||||
"reason": e.Error(),
|
||||
}).Error("Netdb Startup failed")
|
||||
r.Stop()
|
||||
}
|
||||
log.Debug("Exiting router mainloop")
|
||||
}
|
||||
|
111
lib/su3/su3.go
111
lib/su3/su3.go
@ -78,8 +78,13 @@ import (
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
type SignatureType string
|
||||
|
||||
const (
|
||||
@ -190,11 +195,13 @@ type SU3 struct {
|
||||
}
|
||||
|
||||
func (su3 *SU3) Content(publicKey interface{}) io.Reader {
|
||||
log.WithField("signer_id", su3.SignerID).Debug("Accessing SU3 content")
|
||||
su3.publicKey = publicKey
|
||||
return su3.contentReader
|
||||
}
|
||||
|
||||
func (su3 *SU3) Signature() io.Reader {
|
||||
log.Debug("Accessing SU3 signature")
|
||||
return su3.signatureReader
|
||||
}
|
||||
|
||||
@ -202,45 +209,57 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
|
||||
// We will buffer everything up to the content, so that once we know
|
||||
// the hash type being used for the signature, we can write these bytes
|
||||
// into the hash.
|
||||
log.Debug("Starting to read SU3 file")
|
||||
var buff bytes.Buffer
|
||||
|
||||
// Magic bytes.
|
||||
mbytes := make([]byte, len(magicBytes))
|
||||
l, err := reader.Read(mbytes)
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read magic bytes")
|
||||
return nil, fmt.Errorf("reading magic bytes: %w", err)
|
||||
}
|
||||
if l != len(mbytes) {
|
||||
log.Error("Missing magic bytes")
|
||||
return nil, ErrMissingMagicBytes
|
||||
}
|
||||
if string(mbytes) != magicBytes {
|
||||
log.Error("Invalid magic bytes")
|
||||
return nil, ErrMissingMagicBytes
|
||||
}
|
||||
buff.Write(mbytes)
|
||||
log.Debug("Magic bytes verified")
|
||||
|
||||
// Unused byte 6.
|
||||
unused := [1]byte{}
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read unused byte 6")
|
||||
return nil, fmt.Errorf("reading unused byte 6: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
log.Error("Missing unused byte 6")
|
||||
return nil, ErrMissingUnusedByte6
|
||||
}
|
||||
buff.Write(unused[:])
|
||||
log.Debug("Read unused byte 6")
|
||||
|
||||
// SU3 file format version (always 0).
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read SU3 file format version")
|
||||
return nil, fmt.Errorf("reading SU3 file format version: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
log.Error("Missing SU3 file format version")
|
||||
return nil, ErrMissingFileFormatVersion
|
||||
}
|
||||
if unused[0] != 0x00 {
|
||||
log.Error("Invalid SU3 file format version")
|
||||
return nil, ErrMissingFileFormatVersion
|
||||
}
|
||||
buff.Write(unused[:])
|
||||
log.Debug("SU3 file format version verified")
|
||||
|
||||
su3 = &SU3{
|
||||
mut: sync.Mutex{},
|
||||
@ -251,200 +270,258 @@ func Read(reader io.Reader) (su3 *SU3, err error) {
|
||||
sigTypeBytes := [2]byte{}
|
||||
l, err = reader.Read(sigTypeBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read signature type")
|
||||
return nil, fmt.Errorf("reading signature type: %w", err)
|
||||
}
|
||||
if l != 2 {
|
||||
log.Error("Missing signature type")
|
||||
return nil, ErrMissingSignatureType
|
||||
}
|
||||
sigType, ok := sigTypes[sigTypeBytes]
|
||||
if !ok {
|
||||
log.WithField("signature_type", sigTypeBytes).Error("Unsupported signature type")
|
||||
return nil, ErrUnsupportedSignatureType
|
||||
}
|
||||
su3.SignatureType = sigType
|
||||
buff.Write(sigTypeBytes[:])
|
||||
log.WithField("signature_type", sigType).Debug("Signature type read")
|
||||
|
||||
// Signature length.
|
||||
sigLengthBytes := [2]byte{}
|
||||
l, err = reader.Read(sigLengthBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read signature length")
|
||||
return nil, fmt.Errorf("reading signature length: %w", err)
|
||||
}
|
||||
if l != 2 {
|
||||
log.Error("Missing signature length")
|
||||
return nil, ErrMissingSignatureLength
|
||||
}
|
||||
sigLen := binary.BigEndian.Uint16(sigLengthBytes[:])
|
||||
// TODO check that sigLen is the correct length for sigType.
|
||||
su3.SignatureLength = sigLen
|
||||
buff.Write(sigLengthBytes[:])
|
||||
log.WithField("signature_length", sigLen).Debug("Signature length read")
|
||||
|
||||
// Unused byte 12.
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read unused byte 12")
|
||||
return nil, fmt.Errorf("reading unused byte 12: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
log.Error("Missing unused byte 12")
|
||||
return nil, ErrMissingUnusedByte12
|
||||
}
|
||||
buff.Write(unused[:])
|
||||
log.Debug("Read unused byte 12")
|
||||
|
||||
// Version length.
|
||||
verLengthBytes := [1]byte{}
|
||||
l, err = reader.Read(verLengthBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read version length")
|
||||
return nil, fmt.Errorf("reading version length: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
log.Error("Missing version length")
|
||||
return nil, ErrMissingVersionLength
|
||||
}
|
||||
verLen := binary.BigEndian.Uint16([]byte{0x00, verLengthBytes[0]})
|
||||
if verLen < 16 {
|
||||
log.WithField("version_length", verLen).Error("Version length too short")
|
||||
return nil, ErrVersionTooShort
|
||||
}
|
||||
buff.Write(verLengthBytes[:])
|
||||
log.WithField("version_length", verLen).Debug("Version length read")
|
||||
|
||||
// Unused byte 14.
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read unused byte 14")
|
||||
return nil, fmt.Errorf("reading unused byte 14: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
log.Error("Missing unused byte 14")
|
||||
return nil, ErrMissingUnusedByte14
|
||||
}
|
||||
buff.Write(unused[:])
|
||||
log.Debug("Read unused byte 14")
|
||||
|
||||
// Signer ID length.
|
||||
sigIDLengthBytes := [1]byte{}
|
||||
l, err = reader.Read(sigIDLengthBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read signer ID length")
|
||||
return nil, fmt.Errorf("reading signer id length: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
log.Error("Missing signer ID length")
|
||||
return nil, ErrMissingSignerIDLength
|
||||
}
|
||||
signIDLen := binary.BigEndian.Uint16([]byte{0x00, sigIDLengthBytes[0]})
|
||||
buff.Write(sigIDLengthBytes[:])
|
||||
log.WithField("signer_id_length", signIDLen).Debug("Signer ID length read")
|
||||
|
||||
// Content length.
|
||||
contentLengthBytes := [8]byte{}
|
||||
l, err = reader.Read(contentLengthBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read content length")
|
||||
return nil, fmt.Errorf("reading content length: %w", err)
|
||||
}
|
||||
if l != 8 {
|
||||
log.Error("Missing content length")
|
||||
return nil, ErrMissingContentLength
|
||||
}
|
||||
contentLen := binary.BigEndian.Uint64(contentLengthBytes[:])
|
||||
su3.ContentLength = contentLen
|
||||
buff.Write(contentLengthBytes[:])
|
||||
log.WithField("content_length", contentLen).Debug("Content length read")
|
||||
|
||||
// Unused byte 24.
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read unused byte 24")
|
||||
return nil, fmt.Errorf("reading unused byte 24: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
log.Error("Missing unused byte 24")
|
||||
return nil, ErrMissingUnusedByte24
|
||||
}
|
||||
buff.Write(unused[:])
|
||||
log.Debug("Read unused byte 24")
|
||||
|
||||
// File type.
|
||||
fileTypeBytes := [1]byte{}
|
||||
l, err = reader.Read(fileTypeBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read file type")
|
||||
return nil, fmt.Errorf("reading file type: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
log.Error("Missing file type")
|
||||
return nil, ErrMissingFileType
|
||||
}
|
||||
fileType, ok := fileTypes[fileTypeBytes[0]]
|
||||
if !ok {
|
||||
log.WithField("file_type_byte", fileTypeBytes[0]).Error("Invalid file type")
|
||||
return nil, ErrMissingFileType
|
||||
}
|
||||
su3.FileType = fileType
|
||||
buff.Write(fileTypeBytes[:])
|
||||
log.WithField("file_type", fileType).Debug("File type read")
|
||||
|
||||
// Unused byte 26.
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read unused byte 26")
|
||||
return nil, fmt.Errorf("reading unused byte 26: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
log.Error("Missing unused byte 26")
|
||||
return nil, ErrMissingUnusedByte26
|
||||
}
|
||||
buff.Write(unused[:])
|
||||
log.Debug("Read unused byte 26")
|
||||
|
||||
// Content type.
|
||||
contentTypeBytes := [1]byte{}
|
||||
l, err = reader.Read(contentTypeBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read content type")
|
||||
return nil, fmt.Errorf("reading content type: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
log.Error("Missing content type")
|
||||
return nil, ErrMissingContentType
|
||||
}
|
||||
contentType, ok := contentTypes[contentTypeBytes[0]]
|
||||
if !ok {
|
||||
log.WithField("content_type_byte", contentTypeBytes[0]).Error("Invalid content type")
|
||||
return nil, ErrMissingContentType
|
||||
}
|
||||
su3.ContentType = contentType
|
||||
buff.Write(contentTypeBytes[:])
|
||||
log.WithField("content_type", contentType).Debug("Content type read")
|
||||
|
||||
// Unused bytes 28-39.
|
||||
for i := 0; i < 12; i++ {
|
||||
l, err = reader.Read(unused[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read unused bytes 28-39")
|
||||
return nil, fmt.Errorf("reading unused bytes 28-39: %w", err)
|
||||
}
|
||||
if l != 1 {
|
||||
log.WithField("byte_number", 28+i).Error("Missing unused byte")
|
||||
return nil, ErrMissingUnusedBytes28To39
|
||||
}
|
||||
buff.Write(unused[:])
|
||||
}
|
||||
log.Debug("Read unused bytes 28-39")
|
||||
|
||||
// Version.
|
||||
versionBytes := make([]byte, verLen)
|
||||
l, err = reader.Read(versionBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.Debug("Read unused bytes 28-39")
|
||||
return nil, fmt.Errorf("reading version: %w", err)
|
||||
}
|
||||
if l != int(verLen) {
|
||||
log.Error("Missing version")
|
||||
return nil, ErrMissingVersion
|
||||
}
|
||||
version := strings.TrimRight(string(versionBytes), "\x00")
|
||||
su3.Version = version
|
||||
buff.Write(versionBytes[:])
|
||||
log.WithField("version", version).Debug("Version read")
|
||||
|
||||
// Signer ID.
|
||||
signerIDBytes := make([]byte, signIDLen)
|
||||
l, err = reader.Read(signerIDBytes[:])
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Failed to read signer ID")
|
||||
return nil, fmt.Errorf("reading signer id: %w", err)
|
||||
}
|
||||
if l != int(signIDLen) {
|
||||
log.Error("Missing signer ID")
|
||||
return nil, ErrMissingSignerID
|
||||
}
|
||||
signerID := string(signerIDBytes)
|
||||
su3.SignerID = signerID
|
||||
buff.Write(signerIDBytes[:])
|
||||
log.WithField("signer_id", signerID).Debug("Signer ID read")
|
||||
|
||||
su3.contentReader = &contentReader{
|
||||
su3: su3,
|
||||
}
|
||||
log.Debug("Content reader initialized")
|
||||
switch sigType {
|
||||
case RSA_SHA256_2048:
|
||||
su3.contentReader.hash = sha256.New()
|
||||
log.Debug("Using SHA256 hash for content")
|
||||
case RSA_SHA512_4096:
|
||||
su3.contentReader.hash = sha512.New()
|
||||
log.Debug("Using SHA512 hash for content")
|
||||
}
|
||||
|
||||
if su3.contentReader.hash != nil {
|
||||
su3.contentReader.hash.Write(buff.Bytes())
|
||||
log.Debug("Wrote header to content hash")
|
||||
}
|
||||
|
||||
su3.signatureReader = &signatureReader{
|
||||
su3: su3,
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"signature_type": su3.SignatureType,
|
||||
"file_type": su3.FileType,
|
||||
"content_type": su3.ContentType,
|
||||
"version": su3.Version,
|
||||
"signer_id": su3.SignerID,
|
||||
}).Debug("SU3 file read successfully")
|
||||
|
||||
return su3, nil
|
||||
}
|
||||
|
||||
@ -456,6 +533,7 @@ type fixedLengthReader struct {
|
||||
|
||||
func (r *fixedLengthReader) Read(p []byte) (n int, err error) {
|
||||
if r.readSoFar >= r.length {
|
||||
log.Debug("Fixed length reader: EOF reached")
|
||||
return 0, io.EOF
|
||||
}
|
||||
if uint64(len(p)) > r.length-r.readSoFar {
|
||||
@ -463,6 +541,11 @@ func (r *fixedLengthReader) Read(p []byte) (n int, err error) {
|
||||
}
|
||||
n, err = r.reader.Read(p)
|
||||
r.readSoFar += uint64(n)
|
||||
log.WithFields(logrus.Fields{
|
||||
"bytes_read": n,
|
||||
"total_read": r.readSoFar,
|
||||
"total_length": r.length,
|
||||
}).Debug("Fixed length reader: Read operation")
|
||||
return n, err
|
||||
}
|
||||
|
||||
@ -478,6 +561,7 @@ func (r *contentReader) Read(p []byte) (n int, err error) {
|
||||
defer r.su3.mut.Unlock()
|
||||
|
||||
if r.finished {
|
||||
log.Warn("Attempt to read content after finishing")
|
||||
return 0, errors.New("out of bytes, maybe you read the signature before you read the content")
|
||||
}
|
||||
|
||||
@ -487,16 +571,20 @@ func (r *contentReader) Read(p []byte) (n int, err error) {
|
||||
readSoFar: 0,
|
||||
reader: r.su3.reader,
|
||||
}
|
||||
log.WithField("content_length", r.su3.ContentLength).Debug("Initialized content reader")
|
||||
}
|
||||
|
||||
l, err := r.reader.Read(p)
|
||||
|
||||
if err != nil && !errors.Is(err, io.EOF) {
|
||||
log.WithError(err).Error("Error reading content")
|
||||
return l, fmt.Errorf("reading content: %w", err)
|
||||
} else if errors.Is(err, io.EOF) && r.reader.readSoFar != r.su3.ContentLength {
|
||||
log.Error("Content shorter than expected")
|
||||
return l, ErrMissingContent
|
||||
} else if errors.Is(err, io.EOF) {
|
||||
r.finished = true
|
||||
log.Debug("Finished reading content")
|
||||
}
|
||||
|
||||
if r.hash != nil {
|
||||
@ -505,37 +593,47 @@ func (r *contentReader) Read(p []byte) (n int, err error) {
|
||||
|
||||
if r.finished {
|
||||
if r.su3.publicKey == nil {
|
||||
log.Error("No public key provided for signature verification")
|
||||
return l, ErrInvalidSignature
|
||||
}
|
||||
r.su3.signatureReader.getBytes()
|
||||
if r.su3.signatureReader.err != nil {
|
||||
log.WithError(r.su3.signatureReader.err).Error("Failed to get signature bytes")
|
||||
return l, r.su3.signatureReader.err
|
||||
}
|
||||
log.WithField("signature_type", r.su3.SignatureType).Debug("Verifying signature")
|
||||
// TODO support all signature types
|
||||
switch r.su3.SignatureType {
|
||||
case RSA_SHA256_2048:
|
||||
var pubKey *rsa.PublicKey
|
||||
if k, ok := r.su3.publicKey.(*rsa.PublicKey); !ok {
|
||||
log.Error("Invalid public key type")
|
||||
return l, ErrInvalidPublicKey
|
||||
} else {
|
||||
pubKey = k
|
||||
}
|
||||
err := rsa.VerifyPKCS1v15(pubKey, 0, r.hash.Sum(nil), r.su3.signatureReader.bytes)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Signature verification failed")
|
||||
return l, ErrInvalidSignature
|
||||
}
|
||||
log.Debug("Signature verified successfully")
|
||||
case RSA_SHA512_4096:
|
||||
var pubKey *rsa.PublicKey
|
||||
if k, ok := r.su3.publicKey.(*rsa.PublicKey); !ok {
|
||||
log.Error("Invalid public key type")
|
||||
return l, ErrInvalidPublicKey
|
||||
} else {
|
||||
pubKey = k
|
||||
}
|
||||
err := rsa.VerifyPKCS1v15(pubKey, 0, r.hash.Sum(nil), r.su3.signatureReader.bytes)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Signature verification failed")
|
||||
return l, ErrInvalidSignature
|
||||
}
|
||||
log.Debug("Signature verified successfully")
|
||||
default:
|
||||
log.WithField("signature_type", r.su3.SignatureType).Error("Unsupported signature type")
|
||||
return l, ErrUnsupportedSignatureType
|
||||
}
|
||||
}
|
||||
@ -551,10 +649,13 @@ type signatureReader struct {
|
||||
}
|
||||
|
||||
func (r *signatureReader) getBytes() {
|
||||
log.Debug("Getting signature bytes")
|
||||
// If content hasn't been read yet, throw it away.
|
||||
if !r.su3.contentReader.finished {
|
||||
log.Warn("Content not fully read, reading remaining content")
|
||||
_, err := ioutil.ReadAll(r.su3.contentReader)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read remaining content")
|
||||
r.err = fmt.Errorf("reading content: %w", err)
|
||||
return
|
||||
}
|
||||
@ -569,12 +670,15 @@ func (r *signatureReader) getBytes() {
|
||||
sigBytes, err := ioutil.ReadAll(reader)
|
||||
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read signature")
|
||||
r.err = fmt.Errorf("reading signature: %w", err)
|
||||
} else if reader.readSoFar != uint64(r.su3.SignatureLength) {
|
||||
log.Error("Signature shorter than expected")
|
||||
r.err = ErrMissingSignature
|
||||
} else {
|
||||
r.bytes = sigBytes
|
||||
r.reader = bytes.NewReader(sigBytes)
|
||||
log.WithField("signature_length", len(sigBytes)).Debug("Signature bytes read successfully")
|
||||
}
|
||||
}
|
||||
|
||||
@ -582,10 +686,15 @@ func (r *signatureReader) Read(p []byte) (n int, err error) {
|
||||
r.su3.mut.Lock()
|
||||
defer r.su3.mut.Unlock()
|
||||
if len(r.bytes) == 0 {
|
||||
log.Debug("Signature bytes not yet read, getting bytes")
|
||||
r.getBytes()
|
||||
}
|
||||
if r.err != nil {
|
||||
log.WithError(r.err).Error("Error encountered while getting signature bytes")
|
||||
return 0, r.err
|
||||
}
|
||||
return r.reader.Read(p)
|
||||
// return r.reader.Read(p)
|
||||
n, err = r.reader.Read(p)
|
||||
log.WithField("bytes_read", n).Debug("Read from signature")
|
||||
return n, err
|
||||
}
|
||||
|
@ -35,8 +35,8 @@ type Transport interface {
|
||||
// returns nil and an error on error
|
||||
GetSession(routerInfo router_info.RouterInfo) (TransportSession, error)
|
||||
|
||||
// return true if a routerInfo is compatable with this transport
|
||||
Compatable(routerInfo router_info.RouterInfo) bool
|
||||
// return true if a routerInfo is compatible with this transport
|
||||
Compatible(routerInfo router_info.RouterInfo) bool
|
||||
|
||||
// close the transport cleanly
|
||||
// blocks until done
|
||||
@ -72,12 +72,12 @@ func (tmux *TransportMuxer) Close() (err error)
|
||||
```
|
||||
close every transport that this transport muxer has
|
||||
|
||||
#### func (*TransportMuxer) Compatable
|
||||
#### func (*TransportMuxer) Compatible
|
||||
|
||||
```go
|
||||
func (tmux *TransportMuxer) Compatable(routerInfo router_info.RouterInfo) (compat bool)
|
||||
func (tmux *TransportMuxer) Compatible(routerInfo router_info.RouterInfo) (compat bool)
|
||||
```
|
||||
is there a transport that we mux that is compatable with this router info?
|
||||
is there a transport that we mux that is compatible with this router info?
|
||||
|
||||
#### func (*TransportMuxer) GetSession
|
||||
|
||||
|
@ -3,8 +3,11 @@ package transport
|
||||
import (
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_identity"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
// muxes multiple transports into 1 Transport
|
||||
// implements transport.Transport
|
||||
type TransportMuxer struct {
|
||||
@ -14,73 +17,96 @@ type TransportMuxer struct {
|
||||
|
||||
// mux a bunch of transports together
|
||||
func Mux(t ...Transport) (tmux *TransportMuxer) {
|
||||
log.WithField("transport_count", len(t)).Debug("Creating new TransportMuxer")
|
||||
tmux = new(TransportMuxer)
|
||||
tmux.trans = append(tmux.trans, t...)
|
||||
log.Debug("TransportMuxer created successfully")
|
||||
return
|
||||
}
|
||||
|
||||
// set the identity for every transport
|
||||
func (tmux *TransportMuxer) SetIdentity(ident router_identity.RouterIdentity) (err error) {
|
||||
for _, t := range tmux.trans {
|
||||
log.WithField("identity", ident).Debug("TransportMuxer: Setting identity for all transports")
|
||||
for i, t := range tmux.trans {
|
||||
err = t.SetIdentity(ident)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("transport_index", i).Error("TransportMuxer: Failed to set identity for transport")
|
||||
// an error happened let's return and complain
|
||||
return
|
||||
}
|
||||
log.WithField("transport_index", i).Debug("TransportMuxer: Identity set successfully for transport")
|
||||
}
|
||||
log.Debug("TransportMuxer: Identity set successfully for all transports")
|
||||
return
|
||||
}
|
||||
|
||||
// close every transport that this transport muxer has
|
||||
func (tmux *TransportMuxer) Close() (err error) {
|
||||
for _, t := range tmux.trans {
|
||||
log.Debug("TransportMuxer: Closing all transports")
|
||||
for i, t := range tmux.trans {
|
||||
err = t.Close()
|
||||
if t != nil {
|
||||
// TODO: handle error (?)
|
||||
log.WithError(err).WithField("transport_index", i).Warn("TransportMuxer: Error closing transport")
|
||||
} else {
|
||||
log.WithField("transport_index", i).Debug("TransportMuxer: Transport closed successfully")
|
||||
}
|
||||
}
|
||||
log.Debug("TransportMuxer: All transports closed")
|
||||
return
|
||||
}
|
||||
|
||||
// the name of this transport with the names of all the ones that we mux
|
||||
func (tmux *TransportMuxer) Name() string {
|
||||
log.Debug("TransportMuxer: Generating muxed transport name")
|
||||
name := "Muxed Transport: "
|
||||
for _, t := range tmux.trans {
|
||||
name += t.Name() + ", "
|
||||
}
|
||||
return name[len(name)-3:]
|
||||
// return name[len(name)-3:]
|
||||
_name := name[len(name)-3:]
|
||||
log.WithField("name", _name).Debug("TransportMuxer: Muxed transport name generated")
|
||||
return _name
|
||||
}
|
||||
|
||||
// get a transport session given a router info
|
||||
// return session and nil if successful
|
||||
// return nil and ErrNoTransportAvailable if we failed to get a session
|
||||
func (tmux *TransportMuxer) GetSession(routerInfo router_info.RouterInfo) (s TransportSession, err error) {
|
||||
for _, t := range tmux.trans {
|
||||
log.WithField("router_info", routerInfo.String()).Debug("TransportMuxer: Attempting to get session")
|
||||
for i, t := range tmux.trans {
|
||||
// pick the first one that is compatable
|
||||
if t.Compatable(routerInfo) {
|
||||
if t.Compatible(routerInfo) {
|
||||
log.WithField("transport_index", i).Debug("TransportMuxer: Found compatible transport, attempting to get session")
|
||||
// try to get a session
|
||||
s, err = t.GetSession(routerInfo)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("transport_index", i).Warn("TransportMuxer: Failed to get session from compatible transport")
|
||||
// we could not get a session
|
||||
// try the next transport
|
||||
continue
|
||||
}
|
||||
// we got a session
|
||||
log.WithField("transport_index", i).Debug("TransportMuxer: Successfully got session from transport")
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Error("TransportMuxer: Failed to get session, no compatible transport available")
|
||||
// we failed to get a session for this routerInfo
|
||||
err = ErrNoTransportAvailable
|
||||
return
|
||||
}
|
||||
|
||||
// is there a transport that we mux that is compatable with this router info?
|
||||
func (tmux *TransportMuxer) Compatable(routerInfo router_info.RouterInfo) (compat bool) {
|
||||
for _, t := range tmux.trans {
|
||||
if t.Compatable(routerInfo) {
|
||||
func (tmux *TransportMuxer) Compatible(routerInfo router_info.RouterInfo) (compat bool) {
|
||||
log.WithField("router_info", routerInfo.String()).Debug("TransportMuxer: Checking compatibility")
|
||||
for i, t := range tmux.trans {
|
||||
if t.Compatible(routerInfo) {
|
||||
log.WithField("transport_index", i).Debug("TransportMuxer: Found compatible transport")
|
||||
compat = true
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Debug("TransportMuxer: No compatible transport found")
|
||||
return
|
||||
}
|
||||
|
@ -1,270 +1,300 @@
|
||||
|
||||
# noise
|
||||
--
|
||||
import "github.com/go-i2p/go-i2p/lib/transport/noise"
|
||||
|
||||
## Overview
|
||||
|
||||
The `noise` package implements the Noise Protocol to establish secure, authenticated sessions over TCP. This package includes functions for session management, handshake initiation, packet encryption, decryption, and transport abstraction.
|
||||
|
||||
|
||||
## Usage
|
||||
- [handshake.go](#handshakego)
|
||||
- [i2np.go](#i2npgo)
|
||||
- [incoming_handshake.go](#incoming_handshakego)
|
||||
- [outgoing_handshake.go](#outgoing_handshakego)
|
||||
- [noise_constants.go](#noise_constantsgo)
|
||||
- [read_session.go](#read_sessiongo)
|
||||
- [session.go](#sessiongo)
|
||||
- [transport.go](#transportgo)
|
||||
- [write_session.go](#write_sessiongo)
|
||||
|
||||
---
|
||||
|
||||
## handshake.go
|
||||
|
||||
Defines the `Handshake` function, which initiates the Noise handshake process for secure, authenticated sessions.
|
||||
|
||||
### Package
|
||||
|
||||
```go
|
||||
const FlushLimit = 640 * 1024
|
||||
package noise
|
||||
```
|
||||
|
||||
#### type Noise
|
||||
### Imports
|
||||
|
||||
```go
|
||||
type Noise struct {
|
||||
noise.Config
|
||||
router_address.RouterAddress // always the local addr
|
||||
*noise.HandshakeState
|
||||
sync.Mutex
|
||||
import (
|
||||
"sync"
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
)
|
||||
```
|
||||
|
||||
HandshakeStateResponsibility bool
|
||||
### Variables
|
||||
|
||||
- **`log`**: Logger instance for capturing debug and error messages related to the handshake process.
|
||||
|
||||
### Function: `Handshake`
|
||||
|
||||
#### Definition
|
||||
|
||||
```go
|
||||
func (c *NoiseTransport) Handshake(routerInfo router_info.RouterInfo) error
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
- `routerInfo`: Information about the router with which the handshake is established.
|
||||
|
||||
#### Returns
|
||||
- `error`: Returns `nil` on success, or an error if the handshake fails.
|
||||
|
||||
#### Description
|
||||
The `Handshake` function initiates an authenticated handshake with a router, establishing a secure session.
|
||||
|
||||
#### Workflow
|
||||
1. **Logging Start**: Logs initiation of the handshake.
|
||||
2. **Lock Mutex**: Locks `c.Mutex` to prevent concurrent access.
|
||||
3. **Session Retrieval**: Calls `c.getSession(routerInfo)`.
|
||||
4. **Condition Variable Setup**: Sets a `Cond` for the session.
|
||||
5. **Outgoing Handshake**: Executes `RunOutgoingHandshake`.
|
||||
6. **Completion Broadcast**: Broadcasts to waiting goroutines.
|
||||
7. **Finalize and Unlock**: Logs success.
|
||||
|
||||
---
|
||||
|
||||
## i2np.go
|
||||
|
||||
Provides functions to queue and send I2NP messages using a `NoiseSession`.
|
||||
|
||||
### Package
|
||||
|
||||
```go
|
||||
package noise
|
||||
```
|
||||
|
||||
### Imports
|
||||
|
||||
```go
|
||||
import "github.com/go-i2p/go-i2p/lib/i2np"
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
#### `QueueSendI2NP`
|
||||
|
||||
Queues an I2NP message for sending.
|
||||
|
||||
```go
|
||||
func (s *NoiseSession) QueueSendI2NP(msg i2np.I2NPMessage)
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
- `msg`: The I2NP message.
|
||||
|
||||
---
|
||||
|
||||
#### `SendQueueSize`
|
||||
|
||||
Returns the size of the send queue.
|
||||
|
||||
```go
|
||||
func (s *NoiseSession) SendQueueSize() int
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `ReadNextI2NP`
|
||||
|
||||
Attempts to read the next I2NP message from the queue.
|
||||
|
||||
```go
|
||||
func (s *NoiseSession) ReadNextI2NP() (i2np.I2NPMessage, error)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## incoming_handshake.go
|
||||
|
||||
Defines functions for the incoming (receiver) side of the handshake.
|
||||
|
||||
### Functions
|
||||
|
||||
#### `ComposeReceiverHandshakeMessage`
|
||||
|
||||
Creates a receiver handshake message using Noise patterns.
|
||||
|
||||
```go
|
||||
func ComposeReceiverHandshakeMessage(s noise.DHKey, rs []byte, payload []byte, ePrivate []byte) (negData, msg []byte, state *noise.HandshakeState, err error)
|
||||
```
|
||||
|
||||
- **`s`**: Static Diffie-Hellman key.
|
||||
- **`rs`**: Remote static key.
|
||||
- **`payload`**: Optional payload data.
|
||||
- **`ePrivate`**: Private ephemeral key.
|
||||
|
||||
---
|
||||
|
||||
#### `RunIncomingHandshake`
|
||||
|
||||
Executes an incoming handshake process.
|
||||
|
||||
```go
|
||||
func (c *NoiseSession) RunIncomingHandshake() error
|
||||
```
|
||||
|
||||
- Initializes and sends the negotiation data and handshake message.
|
||||
|
||||
---
|
||||
|
||||
## outgoing_handshake.go
|
||||
|
||||
Defines functions for the outgoing (initiator) side of the handshake.
|
||||
|
||||
### Functions
|
||||
|
||||
#### `ComposeInitiatorHandshakeMessage`
|
||||
|
||||
Creates an initiator handshake message.
|
||||
|
||||
```go
|
||||
func ComposeInitiatorHandshakeMessage(s noise.DHKey, rs []byte, payload []byte, ePrivate []byte) (negData, msg []byte, state *noise.HandshakeState, err error)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `RunOutgoingHandshake`
|
||||
|
||||
Executes the outgoing handshake process.
|
||||
|
||||
```go
|
||||
func (c *NoiseSession) RunOutgoingHandshake() error
|
||||
```
|
||||
|
||||
- Sends negotiation data and handshake message.
|
||||
|
||||
---
|
||||
|
||||
## noise_constants.go
|
||||
|
||||
Defines constants and utility functions for configuring Noise protocol parameters.
|
||||
|
||||
### Constants
|
||||
|
||||
```go
|
||||
const (
|
||||
NOISE_DH_CURVE25519 = 1
|
||||
NOISE_CIPHER_CHACHAPOLY = 1
|
||||
NOISE_HASH_SHA256 = 3
|
||||
NOISE_PATTERN_XK = 11
|
||||
uint16Size = 2
|
||||
MaxPayloadSize = 65537
|
||||
)
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
||||
#### `initNegotiationData`
|
||||
|
||||
Initializes negotiation data with default values.
|
||||
|
||||
```go
|
||||
func initNegotiationData(negotiationData []byte) []byte
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## read_session.go
|
||||
|
||||
Functions related to reading encrypted data in a Noise session.
|
||||
|
||||
### Functions
|
||||
|
||||
#### `Read`
|
||||
|
||||
Reads from the Noise session.
|
||||
|
||||
```go
|
||||
func (c *NoiseSession) Read(b []byte) (int, error)
|
||||
```
|
||||
|
||||
#### `decryptPacket`
|
||||
|
||||
Decrypts a packet.
|
||||
|
||||
```go
|
||||
func (c *NoiseSession) decryptPacket(data []byte) (int, []byte, error)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## session.go
|
||||
|
||||
Defines the `NoiseSession` struct and associated methods for session management.
|
||||
|
||||
### Struct: `NoiseSession`
|
||||
|
||||
Defines session properties.
|
||||
|
||||
```go
|
||||
type NoiseSession struct {
|
||||
// Session properties here
|
||||
}
|
||||
```
|
||||
|
||||
wrapper around flynn/noise with just enough options exposed to enable
|
||||
configuring NTCP2 possible and/or relatively intuitive
|
||||
---
|
||||
|
||||
#### func NewNoise
|
||||
## transport.go
|
||||
|
||||
Defines the `NoiseTransport` struct and its methods for session compatibility, accepting connections, etc.
|
||||
|
||||
### Struct: `NoiseTransport`
|
||||
|
||||
```go
|
||||
func NewNoise(ra router_address.RouterAddress) (ns *Noise, err error)
|
||||
```
|
||||
|
||||
#### func (*Noise) Addr
|
||||
|
||||
```go
|
||||
func (ns *Noise) Addr() net.Addr
|
||||
```
|
||||
|
||||
#### func (*Noise) DialNoise
|
||||
|
||||
```go
|
||||
func (ns *Noise) DialNoise(addr router_address.RouterAddress) (conn net.Conn, err error)
|
||||
```
|
||||
|
||||
#### func (*Noise) ListenNoise
|
||||
|
||||
```go
|
||||
func (ns *Noise) ListenNoise() (list NoiseListener, err error)
|
||||
```
|
||||
|
||||
#### func (*Noise) LocalAddr
|
||||
|
||||
```go
|
||||
func (ns *Noise) LocalAddr() net.Addr
|
||||
```
|
||||
|
||||
#### type NoiseConn
|
||||
|
||||
```go
|
||||
type NoiseConn struct {
|
||||
*Noise
|
||||
net.Conn
|
||||
type NoiseTransport struct {
|
||||
sync.Mutex
|
||||
router_identity.RouterIdentity
|
||||
*noise.CipherState
|
||||
Listener net.Listener
|
||||
peerConnections map[data.Hash]transport.TransportSession
|
||||
}
|
||||
```
|
||||
|
||||
#### Methods
|
||||
|
||||
#### func (*NoiseConn) Close
|
||||
- `Compatible`: Checks compatibility.
|
||||
- `Accept`: Accepts a connection.
|
||||
- `Addr`: Returns the address.
|
||||
- `SetIdentity`: Sets the router identity.
|
||||
- `GetSession`: Obtains a session.
|
||||
|
||||
---
|
||||
|
||||
## write_session.go
|
||||
|
||||
Functions for writing encrypted data in a Noise session.
|
||||
|
||||
### Functions
|
||||
|
||||
#### `Write`
|
||||
|
||||
Writes data in a Noise session.
|
||||
|
||||
```go
|
||||
func (nc *NoiseConn) Close() error
|
||||
func (c *NoiseSession) Write(b []byte) (int, error)
|
||||
```
|
||||
Close implements net.Conn.
|
||||
|
||||
#### func (*NoiseConn) Frame
|
||||
#### `encryptPacket`
|
||||
|
||||
Encrypts a packet.
|
||||
|
||||
```go
|
||||
func (nc *NoiseConn) Frame(header, body []byte) (err error)
|
||||
```
|
||||
|
||||
#### func (*NoiseConn) HandshakeStateCreate
|
||||
|
||||
```go
|
||||
func (nc *NoiseConn) HandshakeStateCreate(out, payload []byte) (by []byte, err error)
|
||||
```
|
||||
|
||||
#### func (*NoiseConn) HandshakeStateRead
|
||||
|
||||
```go
|
||||
func (nc *NoiseConn) HandshakeStateRead() (err error)
|
||||
```
|
||||
HandshakeStateRead reads a handshake's state off the socket for storage in the
|
||||
NoiseConn.HandshakeState
|
||||
|
||||
#### func (*NoiseConn) LocalAddr
|
||||
|
||||
```go
|
||||
func (nc *NoiseConn) LocalAddr() net.Addr
|
||||
```
|
||||
LocalAddr implements net.Conn.
|
||||
|
||||
#### func (*NoiseConn) Read
|
||||
|
||||
```go
|
||||
func (nc *NoiseConn) Read(b []byte) (n int, err error)
|
||||
```
|
||||
Read implements net.Conn.
|
||||
|
||||
#### func (*NoiseConn) ReadMsg
|
||||
|
||||
```go
|
||||
func (nc *NoiseConn) ReadMsg(b []byte) (by []byte, err error)
|
||||
```
|
||||
|
||||
#### func (*NoiseConn) RemoteAddr
|
||||
|
||||
```go
|
||||
func (nc *NoiseConn) RemoteAddr() net.Addr
|
||||
```
|
||||
RemoteAddr implements net.Conn.
|
||||
|
||||
#### func (*NoiseConn) SetCipherStates
|
||||
|
||||
```go
|
||||
func (nc *NoiseConn) SetCipherStates(cs1, cs2 *noise.CipherState)
|
||||
```
|
||||
|
||||
#### func (*NoiseConn) SetDeadline
|
||||
|
||||
```go
|
||||
func (nc *NoiseConn) SetDeadline(t time.Time) error
|
||||
```
|
||||
SetDeadline implements net.Conn.
|
||||
|
||||
#### func (*NoiseConn) SetReadDeadline
|
||||
|
||||
```go
|
||||
func (nc *NoiseConn) SetReadDeadline(t time.Time) error
|
||||
```
|
||||
SetReadDeadline implements net.Conn.
|
||||
|
||||
#### func (*NoiseConn) SetWriteDeadline
|
||||
|
||||
```go
|
||||
func (nc *NoiseConn) SetWriteDeadline(t time.Time) error
|
||||
```
|
||||
SetWriteDeadline implements net.Conn.
|
||||
|
||||
#### func (*NoiseConn) Write
|
||||
|
||||
```go
|
||||
func (nc *NoiseConn) Write(b []byte) (n int, err error)
|
||||
```
|
||||
Write implements net.Conn.
|
||||
|
||||
#### type NoiseListener
|
||||
|
||||
```go
|
||||
type NoiseListener struct {
|
||||
*Noise
|
||||
net.Listener
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### func (*NoiseListener) Accept
|
||||
|
||||
```go
|
||||
func (ns *NoiseListener) Accept() (net.Conn, error)
|
||||
```
|
||||
Accept implements net.Listener.
|
||||
|
||||
#### func (*NoiseListener) Addr
|
||||
|
||||
```go
|
||||
func (ns *NoiseListener) Addr() net.Addr
|
||||
```
|
||||
Addr implements net.Listener.
|
||||
|
||||
#### func (*NoiseListener) Close
|
||||
|
||||
```go
|
||||
func (ns *NoiseListener) Close() error
|
||||
```
|
||||
Close implements net.Listener.
|
||||
|
||||
#### type NoisePacketConn
|
||||
|
||||
```go
|
||||
type NoisePacketConn struct {
|
||||
*Noise
|
||||
// this is always a actually a PacketConn
|
||||
net.Conn
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
#### func (*NoisePacketConn) Close
|
||||
|
||||
```go
|
||||
func (n *NoisePacketConn) Close() error
|
||||
```
|
||||
Close implements net.PacketConn. Subtle: this method shadows the method
|
||||
(Conn).Close of NoisePacketConn.Conn.
|
||||
|
||||
#### func (*NoisePacketConn) LocalAddr
|
||||
|
||||
```go
|
||||
func (n *NoisePacketConn) LocalAddr() net.Addr
|
||||
```
|
||||
LocalAddr implements net.PacketConn.
|
||||
|
||||
#### func (*NoisePacketConn) Read
|
||||
|
||||
```go
|
||||
func (*NoisePacketConn) Read(b []byte) (n int, err error)
|
||||
```
|
||||
Read implements net.Conn.
|
||||
|
||||
#### func (*NoisePacketConn) ReadFrom
|
||||
|
||||
```go
|
||||
func (*NoisePacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error)
|
||||
```
|
||||
ReadFrom implements net.PacketConn.
|
||||
|
||||
#### func (*NoisePacketConn) RemoteAddr
|
||||
|
||||
```go
|
||||
func (n *NoisePacketConn) RemoteAddr() net.Addr
|
||||
```
|
||||
RemoteAddr implements net.Conn.
|
||||
|
||||
#### func (*NoisePacketConn) SetDeadline
|
||||
|
||||
```go
|
||||
func (n *NoisePacketConn) SetDeadline(t time.Time) error
|
||||
```
|
||||
SetDeadline implements net.PacketConn. Subtle: this method shadows the method
|
||||
(PacketConn).SetDeadline of NoisePacketConn.PacketConn.
|
||||
|
||||
#### func (*NoisePacketConn) SetReadDeadline
|
||||
|
||||
```go
|
||||
func (n *NoisePacketConn) SetReadDeadline(t time.Time) error
|
||||
```
|
||||
SetReadDeadline implements net.PacketConn. Subtle: this method shadows the
|
||||
method (PacketConn).SetReadDeadline of NoisePacketConn.PacketConn.
|
||||
|
||||
#### func (*NoisePacketConn) SetWriteDeadline
|
||||
|
||||
```go
|
||||
func (n *NoisePacketConn) SetWriteDeadline(t time.Time) error
|
||||
```
|
||||
SetWriteDeadline implements net.PacketConn. Subtle: this method shadows the
|
||||
method (PacketConn).SetWriteDeadline of NoisePacketConn.PacketConn.
|
||||
|
||||
#### func (*NoisePacketConn) Write
|
||||
|
||||
```go
|
||||
func (*NoisePacketConn) Write(b []byte) (n int, err error)
|
||||
```
|
||||
Write implements net.Conn.
|
||||
|
||||
#### func (*NoisePacketConn) WriteTo
|
||||
|
||||
```go
|
||||
func (*NoisePacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error)
|
||||
```
|
||||
WriteTo implements net.PacketConn.
|
||||
func (c *NoiseSession) encryptPacket(data []byte) (int, []byte, error)
|
||||
```
|
670
lib/transport/noise/encrdecr_packet_test.go
Normal file
670
lib/transport/noise/encrdecr_packet_test.go
Normal file
@ -0,0 +1,670 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
"github.com/go-i2p/go-i2p/lib/transport/ntcp"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func (ns *NoiseSession) testEncryptPacket(plaintext []byte) (int, []byte, error) {
|
||||
if ns.CipherState == nil {
|
||||
return 0, nil, fmt.Errorf("CipherState is nil")
|
||||
}
|
||||
|
||||
// Encrypt the data
|
||||
ciphertext, err := ns.CipherState.Encrypt(nil, nil, plaintext)
|
||||
if err != nil {
|
||||
log.Fatalf("unimplemented\nerror:%v\n", err)
|
||||
}
|
||||
|
||||
// Prepend the length of the ciphertext as a 2-byte big-endian value
|
||||
packetLength := uint16(len(ciphertext))
|
||||
packet := make([]byte, 2+len(ciphertext))
|
||||
binary.BigEndian.PutUint16(packet[:2], packetLength)
|
||||
copy(packet[2:], ciphertext)
|
||||
|
||||
return len(packet), packet, nil
|
||||
}
|
||||
|
||||
func (ns *NoiseSession) testPacketDeux(packet []byte) (int, []byte, error) {
|
||||
if ns.CipherState == nil {
|
||||
return 0, nil, fmt.Errorf("CipherState is nil")
|
||||
}
|
||||
|
||||
if len(packet) < 2 {
|
||||
return 0, nil, fmt.Errorf("Packet too short to contain length prefix")
|
||||
}
|
||||
|
||||
// Extract the length prefix
|
||||
packetLength := binary.BigEndian.Uint16(packet[:2])
|
||||
|
||||
if len(packet[2:]) < int(packetLength) {
|
||||
return 0, nil, fmt.Errorf("Packet data is shorter than indicated length")
|
||||
}
|
||||
|
||||
ciphertext := packet[2 : 2+packetLength]
|
||||
|
||||
// Decrypt the data
|
||||
plaintext, err := ns.CipherState.Decrypt(nil, nil, ciphertext)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
return len(plaintext), plaintext, nil
|
||||
}
|
||||
|
||||
func TestEncryptDecryptPacketOffline(t *testing.T) {
|
||||
// Generate static keypairs
|
||||
initiatorStatic, err := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate initiator static keypair: %v", err)
|
||||
}
|
||||
responderStatic, err := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate responder static keypair: %v", err)
|
||||
}
|
||||
|
||||
pattern := noise.HandshakeXK
|
||||
cipherSuite := noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256)
|
||||
|
||||
// Negotiation
|
||||
negData := initNegotiationData(nil)
|
||||
prologue := make([]byte, 2, uint16Size+len(negData))
|
||||
binary.BigEndian.PutUint16(prologue, uint16(len(negData)))
|
||||
prologue = append(prologue, negData...)
|
||||
|
||||
// Handshake
|
||||
initiatorHS, err := noise.NewHandshakeState(noise.Config{
|
||||
StaticKeypair: initiatorStatic,
|
||||
Initiator: true,
|
||||
Pattern: pattern,
|
||||
CipherSuite: cipherSuite,
|
||||
Prologue: prologue,
|
||||
PeerStatic: responderStatic.Public, // Must set this
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create initiator handshake state: %v", err)
|
||||
}
|
||||
|
||||
responderHS, err := noise.NewHandshakeState(noise.Config{
|
||||
StaticKeypair: responderStatic,
|
||||
Initiator: false,
|
||||
Pattern: pattern,
|
||||
CipherSuite: cipherSuite,
|
||||
Prologue: prologue,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create responder handshake state: %v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
initiatorSendCS *noise.CipherState
|
||||
initiatorRecvCS *noise.CipherState
|
||||
responderSendCS *noise.CipherState
|
||||
responderRecvCS *noise.CipherState
|
||||
)
|
||||
|
||||
// Simulate the handshake message exchange
|
||||
|
||||
// Message 1: Initiator -> Responder
|
||||
msg1, cs0, cs1, err := initiatorHS.WriteMessage(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Initiator failed to write handshake message 1: %v", err)
|
||||
}
|
||||
if cs0 != nil || cs1 != nil {
|
||||
t.Fatalf("Initiator should not have CipherStates after message 1")
|
||||
}
|
||||
|
||||
// Responder processes message 1
|
||||
_, cs0, cs1, err = responderHS.ReadMessage(nil, msg1)
|
||||
if err != nil {
|
||||
t.Fatalf("Responder failed to read handshake message 1: %v", err)
|
||||
}
|
||||
if cs0 != nil || cs1 != nil {
|
||||
t.Fatalf("Responder should not have CipherStates after reading message 1")
|
||||
}
|
||||
|
||||
// Responder writes message 2
|
||||
msg2, cs0, cs1, err := responderHS.WriteMessage(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Responder failed to write handshake message 2: %v", err)
|
||||
}
|
||||
if cs0 != nil || cs1 != nil {
|
||||
t.Fatalf("Responder should not have CipherStates after writing message 2")
|
||||
}
|
||||
|
||||
// Initiator processes message 2
|
||||
_, cs0, cs1, err = initiatorHS.ReadMessage(nil, msg2)
|
||||
if err != nil {
|
||||
t.Fatalf("Initiator failed to read handshake message 2: %v", err)
|
||||
}
|
||||
if cs0 != nil || cs1 != nil {
|
||||
t.Fatalf("Initiator should not have CipherStates after reading message 2")
|
||||
}
|
||||
|
||||
// Initiator writes message 3
|
||||
msg3, cs0, cs1, err := initiatorHS.WriteMessage(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Initiator failed to write handshake message 3: %v", err)
|
||||
}
|
||||
if cs0 == nil || cs1 == nil {
|
||||
t.Fatalf("Initiator did not receive CipherStates after writing message 3")
|
||||
}
|
||||
initiatorSendCS = cs0
|
||||
initiatorRecvCS = cs1
|
||||
|
||||
// Responder processes message 3
|
||||
_, cs0, cs1, err = responderHS.ReadMessage(nil, msg3)
|
||||
if err != nil {
|
||||
t.Fatalf("Responder failed to read handshake message 3: %v", err)
|
||||
}
|
||||
if cs0 == nil || cs1 == nil {
|
||||
t.Fatalf("Responder did not receive CipherStates after reading message 3")
|
||||
}
|
||||
responderRecvCS = cs0
|
||||
responderSendCS = cs1
|
||||
|
||||
// Now both parties have the CipherStates
|
||||
|
||||
// Initiator sends a message to Responder
|
||||
initiatorSession := &NoiseSession{
|
||||
CipherState: initiatorSendCS,
|
||||
}
|
||||
responderSession := &NoiseSession{
|
||||
CipherState: responderRecvCS,
|
||||
}
|
||||
|
||||
originalData := []byte("This is a test message.")
|
||||
_, encryptedPacket, err := initiatorSession.encryptPacket(originalData)
|
||||
if err != nil {
|
||||
t.Fatalf("Encryption failed: %v", err)
|
||||
}
|
||||
|
||||
_, decryptedData, err := responderSession.decryptPacket(encryptedPacket[2:])
|
||||
if err != nil {
|
||||
t.Fatalf("Decryption failed: %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, originalData, decryptedData, "Decrypted data does not match the original data")
|
||||
|
||||
// Responder sends a message to Initiator
|
||||
responderSession = &NoiseSession{
|
||||
CipherState: responderSendCS,
|
||||
}
|
||||
initiatorSession = &NoiseSession{
|
||||
CipherState: initiatorRecvCS,
|
||||
}
|
||||
|
||||
responseData := []byte("This is a response message.")
|
||||
_, encryptedResponse, err := responderSession.encryptPacket(responseData)
|
||||
if err != nil {
|
||||
t.Fatalf("Responder encryption failed: %v", err)
|
||||
}
|
||||
|
||||
_, decryptedResponse, err := initiatorSession.decryptPacket(encryptedResponse[2:])
|
||||
if err != nil {
|
||||
t.Fatalf("Initiator decryption failed: %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, responseData, decryptedResponse, "Decrypted response does not match original data")
|
||||
}
|
||||
|
||||
func TestEncryptDecryptPacketObfsOffline(t *testing.T) {
|
||||
// Simulate Bob's Router Hash (RH_B)
|
||||
bobRouterHash := make([]byte, 32)
|
||||
rand.Read(bobRouterHash)
|
||||
|
||||
// Simulate Bob's IV (ri.IV)
|
||||
bobIV := make([]byte, 16)
|
||||
rand.Read(bobIV)
|
||||
|
||||
// Create AES cipher block
|
||||
aesBlock, err := aes.NewCipher(bobRouterHash)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create AES cipher block: %v", err)
|
||||
}
|
||||
|
||||
// Create AES CBC encrypter and decrypter
|
||||
aesEncrypter := cipher.NewCBCEncrypter(aesBlock, bobIV)
|
||||
aesDecrypter := cipher.NewCBCDecrypter(aesBlock, bobIV)
|
||||
|
||||
// Generate static keypairs
|
||||
initiatorStatic, err := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate initiator static keypair: %v", err)
|
||||
}
|
||||
responderStatic, err := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate responder static keypair: %v", err)
|
||||
}
|
||||
|
||||
pattern := noise.HandshakeXK
|
||||
cipherSuite := noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256)
|
||||
|
||||
// Negotiation
|
||||
negData := initNegotiationData(nil)
|
||||
prologue := make([]byte, 2, uint16Size+len(negData))
|
||||
binary.BigEndian.PutUint16(prologue, uint16(len(negData)))
|
||||
prologue = append(prologue, negData...)
|
||||
|
||||
// Alice's Handshake State
|
||||
initiatorHS, err := noise.NewHandshakeState(noise.Config{
|
||||
StaticKeypair: initiatorStatic,
|
||||
Initiator: true,
|
||||
Pattern: pattern,
|
||||
CipherSuite: cipherSuite,
|
||||
Prologue: prologue,
|
||||
PeerStatic: responderStatic.Public, // Bob's static public key
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create initiator handshake state: %v", err)
|
||||
}
|
||||
|
||||
// Bob's Handshake State
|
||||
responderHS, err := noise.NewHandshakeState(noise.Config{
|
||||
StaticKeypair: responderStatic,
|
||||
Initiator: false,
|
||||
Pattern: pattern,
|
||||
CipherSuite: cipherSuite,
|
||||
Prologue: prologue,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create responder handshake state: %v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
initiatorSendCS *noise.CipherState
|
||||
initiatorRecvCS *noise.CipherState
|
||||
responderSendCS *noise.CipherState
|
||||
responderRecvCS *noise.CipherState
|
||||
)
|
||||
|
||||
// Simulate the handshake message exchange
|
||||
|
||||
// -------------------------------
|
||||
// Message 1: Initiator -> Responder
|
||||
// -------------------------------
|
||||
|
||||
// Alice writes message 1
|
||||
msg1, cs0, cs1, err := initiatorHS.WriteMessage(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Initiator failed to write handshake message 1: %v", err)
|
||||
}
|
||||
if cs0 != nil || cs1 != nil {
|
||||
t.Fatalf("Initiator should not have CipherStates after message 1")
|
||||
}
|
||||
|
||||
// Encrypt Alice's ephemeral public key using AES-256-CBC
|
||||
if len(msg1) < 32 {
|
||||
t.Fatalf("Message 1 is too short to contain ephemeral public key")
|
||||
}
|
||||
aliceEphemeralPubKey := msg1[:32] // First 32 bytes
|
||||
encryptedX := make([]byte, len(aliceEphemeralPubKey))
|
||||
aesEncrypter.CryptBlocks(encryptedX, aliceEphemeralPubKey)
|
||||
|
||||
// Construct the modified message 1
|
||||
fullMsg1 := append(encryptedX, msg1[32:]...)
|
||||
|
||||
// -------------------------------
|
||||
// Responder processes message 1
|
||||
// -------------------------------
|
||||
|
||||
// Extract encrypted ephemeral public key
|
||||
encryptedXReceived := fullMsg1[:32]
|
||||
// Decrypt the ephemeral public key
|
||||
decryptedX := make([]byte, len(encryptedXReceived))
|
||||
aesDecrypter.CryptBlocks(decryptedX, encryptedXReceived)
|
||||
|
||||
// Replace the encrypted ephemeral key with the decrypted one
|
||||
modifiedMsg1 := append(decryptedX, fullMsg1[32:]...)
|
||||
|
||||
// Bob reads message 1
|
||||
_, cs0, cs1, err = responderHS.ReadMessage(nil, modifiedMsg1)
|
||||
if err != nil {
|
||||
t.Fatalf("Responder failed to read handshake message 1: %v", err)
|
||||
}
|
||||
if cs0 != nil || cs1 != nil {
|
||||
t.Fatalf("Responder should not have CipherStates after reading message 1")
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Message 2: Responder -> Initiator
|
||||
// -------------------------------
|
||||
|
||||
// Bob writes message 2
|
||||
msg2, cs0, cs1, err := responderHS.WriteMessage(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Responder failed to write handshake message 2: %v", err)
|
||||
}
|
||||
if cs0 != nil || cs1 != nil {
|
||||
t.Fatalf("Responder should not have CipherStates after writing message 2")
|
||||
}
|
||||
|
||||
// Encrypt Bob's ephemeral public key using AES-256-CBC
|
||||
if len(msg2) < 32 {
|
||||
t.Fatalf("Message 2 is too short to contain ephemeral public key")
|
||||
}
|
||||
bobEphemeralPubKey := msg2[:32] // First 32 bytes
|
||||
encryptedY := make([]byte, len(bobEphemeralPubKey))
|
||||
aesEncrypter.CryptBlocks(encryptedY, bobEphemeralPubKey)
|
||||
|
||||
// Construct the modified message 2
|
||||
fullMsg2 := append(encryptedY, msg2[32:]...)
|
||||
|
||||
// -------------------------------
|
||||
// Initiator processes message 2
|
||||
// -------------------------------
|
||||
|
||||
// Extract encrypted ephemeral public key
|
||||
encryptedYReceived := fullMsg2[:32]
|
||||
// Decrypt the ephemeral public key
|
||||
decryptedY := make([]byte, len(encryptedYReceived))
|
||||
aesDecrypter.CryptBlocks(decryptedY, encryptedYReceived)
|
||||
|
||||
// Replace the encrypted ephemeral key with the decrypted one
|
||||
modifiedMsg2 := append(decryptedY, fullMsg2[32:]...)
|
||||
|
||||
// Alice reads message 2
|
||||
_, cs0, cs1, err = initiatorHS.ReadMessage(nil, modifiedMsg2)
|
||||
if err != nil {
|
||||
t.Fatalf("Initiator failed to read handshake message 2: %v", err)
|
||||
}
|
||||
if cs0 != nil || cs1 != nil {
|
||||
t.Fatalf("Initiator should not have CipherStates after reading message 2")
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Message 3: Initiator -> Responder
|
||||
// -------------------------------
|
||||
|
||||
// Alice writes message 3
|
||||
msg3, cs0, cs1, err := initiatorHS.WriteMessage(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Initiator failed to write handshake message 3: %v", err)
|
||||
}
|
||||
if cs0 == nil || cs1 == nil {
|
||||
t.Fatalf("Initiator did not receive CipherStates after writing message 3")
|
||||
}
|
||||
initiatorSendCS = cs0
|
||||
initiatorRecvCS = cs1
|
||||
|
||||
// Responder processes message 3
|
||||
_, cs0, cs1, err = responderHS.ReadMessage(nil, msg3)
|
||||
if err != nil {
|
||||
t.Fatalf("Responder failed to read handshake message 3: %v", err)
|
||||
}
|
||||
if cs0 == nil || cs1 == nil {
|
||||
t.Fatalf("Responder did not receive CipherStates after reading message 3")
|
||||
}
|
||||
responderRecvCS = cs0
|
||||
responderSendCS = cs1
|
||||
|
||||
// Now both parties have the CipherStates
|
||||
|
||||
// Initiator sends a message to Responder
|
||||
initiatorSession := &NoiseSession{
|
||||
CipherState: initiatorSendCS,
|
||||
}
|
||||
responderSession := &NoiseSession{
|
||||
CipherState: responderRecvCS,
|
||||
}
|
||||
|
||||
originalData := []byte("This is a test message.")
|
||||
_, encryptedPacket, err := initiatorSession.encryptPacket(originalData)
|
||||
if err != nil {
|
||||
t.Fatalf("Encryption failed: %v", err)
|
||||
}
|
||||
|
||||
_, decryptedData, err := responderSession.decryptPacket(encryptedPacket[2:])
|
||||
if err != nil {
|
||||
t.Fatalf("Decryption failed: %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, originalData, decryptedData, "Decrypted data does not match the original data")
|
||||
|
||||
// Responder sends a message to Initiator
|
||||
responderSession = &NoiseSession{
|
||||
CipherState: responderSendCS,
|
||||
}
|
||||
initiatorSession = &NoiseSession{
|
||||
CipherState: initiatorRecvCS,
|
||||
}
|
||||
|
||||
responseData := []byte("This is a response message.")
|
||||
_, encryptedResponse, err := responderSession.encryptPacket(responseData)
|
||||
if err != nil {
|
||||
t.Fatalf("Responder encryption failed: %v", err)
|
||||
}
|
||||
|
||||
_, decryptedResponse, err := initiatorSession.decryptPacket(encryptedResponse[2:])
|
||||
if err != nil {
|
||||
t.Fatalf("Initiator decryption failed: %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, responseData, decryptedResponse, "Decrypted response does not match original data")
|
||||
}
|
||||
|
||||
// TestEncryptDecryptPacketObfsOffline tests the encryption and decryption with AES obfuscation
|
||||
func TestEncryptDecryptPacketObfsOfflineWithFunc(t *testing.T) {
|
||||
// Simulate Bob's Router Hash (RH_B)
|
||||
bobRouterHash := make([]byte, 32)
|
||||
rand.Read(bobRouterHash)
|
||||
|
||||
// Simulate Bob's IV (ri.IV)
|
||||
bobIV := make([]byte, 16)
|
||||
rand.Read(bobIV)
|
||||
|
||||
// Create AES symmetric key
|
||||
aesKey := &crypto.AESSymmetricKey{
|
||||
Key: bobRouterHash,
|
||||
IV: bobIV,
|
||||
}
|
||||
|
||||
// Generate static keypairs
|
||||
initiatorStatic, err := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate initiator static keypair: %v", err)
|
||||
}
|
||||
responderStatic, err := noise.DH25519.GenerateKeypair(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate responder static keypair: %v", err)
|
||||
}
|
||||
|
||||
pattern := noise.HandshakeXK
|
||||
cipherSuite := noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256)
|
||||
|
||||
// Negotiation
|
||||
negData := initNegotiationData(nil)
|
||||
prologue := make([]byte, 2+len(negData))
|
||||
binary.BigEndian.PutUint16(prologue, uint16(len(negData)))
|
||||
copy(prologue[2:], negData)
|
||||
|
||||
// Alice's Handshake State
|
||||
initiatorHS, err := noise.NewHandshakeState(noise.Config{
|
||||
StaticKeypair: initiatorStatic,
|
||||
Initiator: true,
|
||||
Pattern: pattern,
|
||||
CipherSuite: cipherSuite,
|
||||
Prologue: prologue,
|
||||
PeerStatic: responderStatic.Public, // Bob's static public key
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create initiator handshake state: %v", err)
|
||||
}
|
||||
|
||||
// Bob's Handshake State
|
||||
responderHS, err := noise.NewHandshakeState(noise.Config{
|
||||
StaticKeypair: responderStatic,
|
||||
Initiator: false,
|
||||
Pattern: pattern,
|
||||
CipherSuite: cipherSuite,
|
||||
Prologue: prologue,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create responder handshake state: %v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
initiatorSendCS *noise.CipherState
|
||||
initiatorRecvCS *noise.CipherState
|
||||
responderSendCS *noise.CipherState
|
||||
responderRecvCS *noise.CipherState
|
||||
)
|
||||
|
||||
// Simulate the handshake message exchange
|
||||
|
||||
// -------------------------------
|
||||
// Message 1: Initiator -> Responder
|
||||
// -------------------------------
|
||||
|
||||
// Alice writes message 1
|
||||
msg1, cs0, cs1, err := initiatorHS.WriteMessage(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Initiator failed to write handshake message 1: %v", err)
|
||||
}
|
||||
if cs0 != nil || cs1 != nil {
|
||||
t.Fatalf("Initiator should not have CipherStates after message 1")
|
||||
}
|
||||
|
||||
// Obfuscate Alice's ephemeral public key in message 1
|
||||
obfuscatedMsg1, err := ntcp.ObfuscateEphemeralKey(msg1, aesKey)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to obfuscate message 1: %v", err)
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Responder processes message 1
|
||||
// -------------------------------
|
||||
|
||||
// Deobfuscate Alice's ephemeral public key in message 1
|
||||
deobfuscatedMsg1, err := ntcp.DeobfuscateEphemeralKey(obfuscatedMsg1, aesKey)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to deobfuscate message 1: %v", err)
|
||||
}
|
||||
|
||||
// Bob reads message 1
|
||||
_, cs0, cs1, err = responderHS.ReadMessage(nil, deobfuscatedMsg1)
|
||||
if err != nil {
|
||||
t.Fatalf("Responder failed to read handshake message 1: %v", err)
|
||||
}
|
||||
if cs0 != nil || cs1 != nil {
|
||||
t.Fatalf("Responder should not have CipherStates after reading message 1")
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Message 2: Responder -> Initiator
|
||||
// -------------------------------
|
||||
|
||||
// Bob writes message 2
|
||||
msg2, cs0, cs1, err := responderHS.WriteMessage(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Responder failed to write handshake message 2: %v", err)
|
||||
}
|
||||
if cs0 != nil || cs1 != nil {
|
||||
t.Fatalf("Responder should not have CipherStates after writing message 2")
|
||||
}
|
||||
|
||||
// Obfuscate Bob's ephemeral public key in message 2
|
||||
obfuscatedMsg2, err := ntcp.ObfuscateEphemeralKey(msg2, aesKey)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to obfuscate message 2: %v", err)
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Initiator processes message 2
|
||||
// -------------------------------
|
||||
|
||||
// Deobfuscate Bob's ephemeral public key in message 2
|
||||
deobfuscatedMsg2, err := ntcp.DeobfuscateEphemeralKey(obfuscatedMsg2, aesKey)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to deobfuscate message 2: %v", err)
|
||||
}
|
||||
|
||||
// Alice reads message 2
|
||||
_, cs0, cs1, err = initiatorHS.ReadMessage(nil, deobfuscatedMsg2)
|
||||
if err != nil {
|
||||
t.Fatalf("Initiator failed to read handshake message 2: %v", err)
|
||||
}
|
||||
if cs0 != nil || cs1 != nil {
|
||||
t.Fatalf("Initiator should not have CipherStates after reading message 2")
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Message 3: Initiator -> Responder
|
||||
// -------------------------------
|
||||
|
||||
// Alice writes message 3
|
||||
msg3, cs0, cs1, err := initiatorHS.WriteMessage(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Initiator failed to write handshake message 3: %v", err)
|
||||
}
|
||||
if cs0 == nil || cs1 == nil {
|
||||
t.Fatalf("Initiator did not receive CipherStates after writing message 3")
|
||||
}
|
||||
initiatorSendCS = cs0
|
||||
initiatorRecvCS = cs1
|
||||
|
||||
// Responder processes message 3
|
||||
_, cs0, cs1, err = responderHS.ReadMessage(nil, msg3)
|
||||
if err != nil {
|
||||
t.Fatalf("Responder failed to read handshake message 3: %v", err)
|
||||
}
|
||||
if cs0 == nil || cs1 == nil {
|
||||
t.Fatalf("Responder did not receive CipherStates after reading message 3")
|
||||
}
|
||||
responderRecvCS = cs0
|
||||
responderSendCS = cs1
|
||||
|
||||
// Now both parties have the CipherStates
|
||||
|
||||
// Initiator sends a message to Responder
|
||||
initiatorSession := &NoiseSession{
|
||||
CipherState: initiatorSendCS,
|
||||
}
|
||||
responderSession := &NoiseSession{
|
||||
CipherState: responderRecvCS,
|
||||
}
|
||||
|
||||
originalData := []byte("This is a test message.")
|
||||
_, encryptedPacket, err := initiatorSession.testEncryptPacket(originalData)
|
||||
if err != nil {
|
||||
t.Fatalf("Encryption failed: %v", err)
|
||||
}
|
||||
|
||||
_, decryptedData, err := responderSession.testPacketDeux(encryptedPacket)
|
||||
if err != nil {
|
||||
t.Fatalf("Decryption failed: %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, originalData, decryptedData, "Decrypted data does not match the original data")
|
||||
|
||||
// Responder sends a message to Initiator
|
||||
responderSession = &NoiseSession{
|
||||
CipherState: responderSendCS,
|
||||
}
|
||||
initiatorSession = &NoiseSession{
|
||||
CipherState: initiatorRecvCS,
|
||||
}
|
||||
|
||||
responseData := []byte("This is a response message.")
|
||||
_, encryptedResponse, err := responderSession.testEncryptPacket(responseData)
|
||||
if err != nil {
|
||||
t.Fatalf("Responder encryption failed: %v", err)
|
||||
}
|
||||
|
||||
_, decryptedResponse, err := initiatorSession.testPacketDeux(encryptedResponse)
|
||||
if err != nil {
|
||||
t.Fatalf("Initiator decryption failed: %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, responseData, decryptedResponse, "Decrypted response does not match original data")
|
||||
}
|
41
lib/transport/noise/handshake.go
Normal file
41
lib/transport/noise/handshake.go
Normal file
@ -0,0 +1,41 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
func (c *NoiseTransport) Handshake(routerInfo router_info.RouterInfo) error {
|
||||
log.WithField("router_info", routerInfo.IdentHash()).Debug("Starting Noise handshake")
|
||||
c.Mutex.Lock()
|
||||
defer c.Mutex.Unlock()
|
||||
session, err := c.getSession(routerInfo)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get session for handshake")
|
||||
return err
|
||||
}
|
||||
log.Debug("Session obtained for handshake")
|
||||
// Set handshakeCond to indicate that this goroutine is committing to
|
||||
// running the handshake.
|
||||
session.(*NoiseSession).Cond = sync.NewCond(&c.Mutex)
|
||||
c.Mutex.Unlock()
|
||||
session.(*NoiseSession).Mutex.Lock()
|
||||
defer session.(*NoiseSession).Mutex.Unlock()
|
||||
c.Mutex.Lock()
|
||||
log.Debug("Running outgoing handshake")
|
||||
if err := session.(*NoiseSession).RunOutgoingHandshake(); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Debug("Outgoing handshake completed successfully")
|
||||
// Wake any other goroutines that are waiting for this handshake to
|
||||
// complete.
|
||||
session.(*NoiseSession).Cond.Broadcast()
|
||||
session.(*NoiseSession).Cond = nil
|
||||
log.Debug("Noise handshake completed successfully")
|
||||
return nil
|
||||
}
|
15
lib/transport/noise/i2np.go
Normal file
15
lib/transport/noise/i2np.go
Normal file
@ -0,0 +1,15 @@
|
||||
package noise
|
||||
|
||||
import "github.com/go-i2p/go-i2p/lib/i2np"
|
||||
|
||||
func (s *NoiseSession) QueueSendI2NP(msg i2np.I2NPMessage) {
|
||||
s.SendQueue.Enqueue(msg)
|
||||
}
|
||||
|
||||
func (s *NoiseSession) SendQueueSize() int {
|
||||
return s.SendQueue.Size()
|
||||
}
|
||||
|
||||
func (s *NoiseSession) ReadNextI2NP() (i2np.I2NPMessage, error) {
|
||||
return i2np.I2NPMessage{}, nil
|
||||
}
|
88
lib/transport/noise/incoming_handshake.go
Normal file
88
lib/transport/noise/incoming_handshake.go
Normal file
@ -0,0 +1,88 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
)
|
||||
|
||||
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")
|
||||
|
||||
negData, msg, state, err := ComposeReceiverHandshakeMessage(c.HandKey, nil, nil, nil)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to compose receiver handshake message")
|
||||
return err
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"negData_length": len(negData),
|
||||
"msg_length": len(msg),
|
||||
}).Debug("Receiver handshake message composed")
|
||||
if _, err = c.Write(negData); err != nil {
|
||||
log.WithError(err).Error("Failed to write negotiation data")
|
||||
return err
|
||||
}
|
||||
log.Debug("Negotiation data written successfully")
|
||||
if _, err = c.Write(msg); err != nil {
|
||||
log.WithError(err).Error("Failed to write handshake message")
|
||||
return err
|
||||
}
|
||||
log.Debug("Handshake message written successfully")
|
||||
log.WithField("state", state).Debug("Handshake state after message write")
|
||||
log.Println(state)
|
||||
c.handshakeComplete = true
|
||||
log.Debug("Incoming handshake completed successfully")
|
||||
return nil
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_address"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
)
|
||||
|
||||
// wrapper around flynn/noise with just enough options exposed to enable configuring NTCP2
|
||||
// possible and/or relatively intuitive
|
||||
type Noise struct {
|
||||
noise.Config
|
||||
router_info.RouterInfo // always the local
|
||||
*noise.HandshakeState
|
||||
|
||||
HandshakeStateResponsibility bool
|
||||
handshakeHash []byte
|
||||
|
||||
send, recv *noise.CipherState
|
||||
|
||||
readMsgBuf []byte
|
||||
writeMsgBuf []byte
|
||||
readBuf []byte
|
||||
}
|
||||
|
||||
var (
|
||||
ex_ns net.Conn = &NoiseConn{}
|
||||
ex_ns_l net.Listener = &NoiseListener{}
|
||||
ex_ns_u net.PacketConn = &NoisePacketConn{}
|
||||
)
|
||||
|
||||
// NewNoise creates a new Noise-based transport with only the config for our side of the connection.
|
||||
// It accepts a RouterInfo which should always be our own RouterInfo.
|
||||
func NewNoise(ri router_info.RouterInfo) (ns *Noise, err error) {
|
||||
ns = &Noise{}
|
||||
ns.RouterInfo = ri
|
||||
// sk, err := ra.StaticKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ns.Config = noise.Config{
|
||||
CipherSuite: noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashSHA256),
|
||||
Pattern: noise.HandshakeXK,
|
||||
// StaticKeypair: ,
|
||||
// StaticKeypair: ,
|
||||
// EphemeralKeypair: ,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ns *Noise) LocalAddr() net.Addr {
|
||||
return &ns.RouterInfo
|
||||
}
|
||||
|
||||
func (ns *Noise) Addr() net.Addr {
|
||||
return ns.LocalAddr()
|
||||
}
|
||||
|
||||
// MatchAddr finds a transport suitable for an incoming RouterAddress
|
||||
func (ns *Noise) MatchAddr(addr net.Addr) (*router_address.RouterAddress, error) {
|
||||
for index, address := range ns.RouterInfo.RouterAddresses() {
|
||||
log.Println("index", index, "address", address)
|
||||
if addr.Network() == address.Network() {
|
||||
return address, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("no suitable address found for type %s from %s", addr.Network(), addr.String())
|
||||
}
|
||||
|
||||
func dialWrapper(network, address string) (net.Conn, error) {
|
||||
switch network {
|
||||
case "SSU24":
|
||||
return net.Dial("udp4", address)
|
||||
case "SSU26":
|
||||
return net.Dial("udp6", address)
|
||||
case "NTCP2":
|
||||
return net.Dial("tcp", address)
|
||||
case "NTCP24":
|
||||
return net.Dial("tcp4", address)
|
||||
case "NTCP26":
|
||||
return net.Dial("tcp6", address)
|
||||
case "NTCP4":
|
||||
return net.Dial("tcp4", address)
|
||||
case "NTCP6":
|
||||
return net.Dial("tcp6", address)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown transport, cannot dial %s", network)
|
||||
}
|
||||
}
|
||||
|
||||
func (ns Noise) DialNoise(addr router_address.RouterAddress) (net.Conn, error) {
|
||||
cfg := ns
|
||||
cfg.Initiator = false
|
||||
network := addr.Network()
|
||||
host, err := addr.Host()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("host error: %s", err)
|
||||
}
|
||||
port, err := addr.Port()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("port error: %s", err)
|
||||
}
|
||||
raddr := net.JoinHostPort(host.String(), port)
|
||||
var netConn net.Conn
|
||||
netConn, err = dialWrapper(network, raddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dial error: %s", err)
|
||||
}
|
||||
cfg.HandshakeState, err = noise.NewHandshakeState(cfg.Config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("handshake state initialization error: %s", err)
|
||||
}
|
||||
laddr, err := ns.MatchAddr(&addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("transport mismatch error %s", err)
|
||||
}
|
||||
// cfg.Config.PeerEphemeral, err = AESDeObfuscateEphemeralKeys()
|
||||
return &NoiseConn{
|
||||
Noise: cfg,
|
||||
Conn: netConn,
|
||||
raddr: addr,
|
||||
laddr: *laddr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ns Noise) ListenNoise(addr router_address.RouterAddress) (list NoiseListener, err error) {
|
||||
cfg := ns
|
||||
cfg.Initiator = false
|
||||
network := "tcp"
|
||||
host, err := addr.Host()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
port, err := addr.Port()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
portNum, _ := strconv.Atoi(port)
|
||||
port = strconv.Itoa(portNum + 1)
|
||||
hostip := net.JoinHostPort(host.String(), port)
|
||||
listener, err := net.Listen(network, hostip)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return NoiseListener{
|
||||
Noise: cfg,
|
||||
Listener: listener,
|
||||
}, nil
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_address"
|
||||
)
|
||||
|
||||
const FlushLimit = 640 * 1024
|
||||
|
||||
type NoiseConn struct {
|
||||
Noise
|
||||
net.Conn
|
||||
sync.Mutex
|
||||
laddr, raddr router_address.RouterAddress
|
||||
lock bool
|
||||
}
|
||||
|
||||
func (ns *NoiseConn) unlockMutex() {
|
||||
if ns.lock {
|
||||
ns.lock = false
|
||||
ns.Mutex.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *NoiseConn) lockMutex() {
|
||||
if !ns.lock {
|
||||
ns.lock = true
|
||||
ns.Mutex.Lock()
|
||||
}
|
||||
}
|
||||
|
||||
// Close implements net.Conn.
|
||||
func (nc *NoiseConn) Close() error {
|
||||
return nc.Conn.Close()
|
||||
}
|
||||
|
||||
// LocalAddr implements net.Conn.
|
||||
func (nc *NoiseConn) LocalAddr() net.Addr {
|
||||
return &nc.laddr
|
||||
}
|
||||
|
||||
// Write implements net.Conn.
|
||||
func (nc *NoiseConn) Write(b []byte) (n int, err error) {
|
||||
nc.lockMutex()
|
||||
if nc.HandshakeState != nil {
|
||||
defer nc.unlockMutex()
|
||||
for nc.HandshakeState != nil && len(b) > 0 {
|
||||
if !nc.Initiator {
|
||||
// If we're the initiator, then we set that in advance and we already know.
|
||||
// If not, we need to read the handshake state first.
|
||||
err = nc.HandshakeStateRead()
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
// if the HandshakeState is not populated here we are the initiator.
|
||||
// we could(should? shouldn't?) check both but for now I'm sticking with what
|
||||
// NoiseConn does
|
||||
if nc.HandshakeState != nil {
|
||||
// choose either the length of b or the maximum length of a message
|
||||
l := min(noise.MaxMsgLen, len(b))
|
||||
// update the HandshakeState using l number of bytes to the write message buffer
|
||||
nc.writeMsgBuf, err = nc.HandshakeStateCreate(nc.writeMsgBuf[:0], b[:l])
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
// write the message buffer to the socket
|
||||
_, err = nc.Conn.Write(nc.writeMsgBuf)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
n += l
|
||||
b = b[l:]
|
||||
}
|
||||
}
|
||||
}
|
||||
nc.unlockMutex()
|
||||
// zero-out the write buffer
|
||||
nc.writeMsgBuf = nc.writeMsgBuf[:0]
|
||||
for len(b) > 0 {
|
||||
outlen := len(nc.writeMsgBuf)
|
||||
l := min(noise.MaxMsgLen, len(b))
|
||||
nc.writeMsgBuf, err = nc.send.Encrypt(append(nc.writeMsgBuf, make([]byte, 4)...), nil, b[:l])
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
err = nc.Frame(nc.writeMsgBuf[outlen:], nc.writeMsgBuf[outlen+4:])
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
n += l
|
||||
b = b[l:]
|
||||
if len(nc.writeMsgBuf) > FlushLimit {
|
||||
_, err = nc.Conn.Write(nc.writeMsgBuf)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
nc.writeMsgBuf = nc.writeMsgBuf[:0]
|
||||
}
|
||||
}
|
||||
if len(nc.writeMsgBuf) > 0 {
|
||||
_, err = nc.Conn.Write(nc.writeMsgBuf)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
nc.writeMsgBuf = nc.writeMsgBuf[:0]
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Read implements net.Conn.
|
||||
func (nc *NoiseConn) Read(b []byte) (n int, err error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// RemoteAddr implements net.Conn.
|
||||
func (nc *NoiseConn) RemoteAddr() net.Addr {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// SetDeadline implements net.Conn.
|
||||
func (nc *NoiseConn) SetDeadline(t time.Time) error {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// SetReadDeadline implements net.Conn.
|
||||
func (nc *NoiseConn) SetReadDeadline(t time.Time) error {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// SetWriteDeadline implements net.Conn.
|
||||
func (nc *NoiseConn) SetWriteDeadline(t time.Time) error {
|
||||
panic("unimplemented")
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
package noise
|
||||
|
||||
import "github.com/flynn/noise"
|
||||
|
||||
// HandshakeStateRead reads a handshake's state off the socket for storage in the
|
||||
// NoiseConn.HandshakeState
|
||||
func (nc *NoiseConn) HandshakeStateRead() (err error) {
|
||||
nc.readMsgBuf, err = nc.ReadMsg(nc.readMsgBuf[:0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var cs1, cs2 *noise.CipherState
|
||||
nc.readBuf, cs1, cs2, err = nc.HandshakeState.ReadMessage(nc.readBuf, nc.readMsgBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nc.SetCipherStates(cs1, cs2)
|
||||
nc.HandshakeStateResponsibility = true
|
||||
//if nc.rfmValidate != nil {
|
||||
//err = nc.rfmValidate(nc.Conn.RemoteAddr(), nc.readMsgBuf)
|
||||
//nc.rfmValidate = nil
|
||||
//return err
|
||||
//}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nc *NoiseConn) HandshakeStateCreate(out, payload []byte) (by []byte, err error) {
|
||||
var cs1, cs2 *noise.CipherState
|
||||
outlen := len(out)
|
||||
out, cs1, cs2, err = nc.HandshakeState.WriteMessage(append(out, make([]byte, 4)...), payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//if nc.rfmValidate != nil {
|
||||
// only applies to responders, not initiators.
|
||||
//nc.rfmValidate = nil
|
||||
//}
|
||||
nc.SetCipherStates(cs1, cs2)
|
||||
nc.HandshakeStateResponsibility = false
|
||||
// nc.readBarrier.Release()
|
||||
return out, nc.Frame(out[outlen:], out[outlen+4:])
|
||||
}
|
||||
|
||||
func (nc *NoiseConn) Frame(header, body []byte) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (nc *NoiseConn) ReadMsg(b []byte) (by []byte, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (nc *NoiseConn) SetCipherStates(cs1, cs2 *noise.CipherState) {
|
||||
if nc.Initiator {
|
||||
nc.send, nc.recv = cs1, cs2
|
||||
} else {
|
||||
nc.send, nc.recv = cs2, cs1
|
||||
}
|
||||
if nc.send != nil {
|
||||
// nc.readBarrier.Release()
|
||||
nc.handshakeHash = nc.HandshakeState.ChannelBinding()
|
||||
nc.HandshakeState = nil
|
||||
}
|
||||
}
|
46
lib/transport/noise/noise_constants.go
Normal file
46
lib/transport/noise/noise_constants.go
Normal file
@ -0,0 +1,46 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
)
|
||||
|
||||
const (
|
||||
NOISE_DH_CURVE25519 = 1
|
||||
|
||||
NOISE_CIPHER_CHACHAPOLY = 1
|
||||
NOISE_CIPHER_AESGCM = 2
|
||||
|
||||
NOISE_HASH_SHA256 = 3
|
||||
|
||||
NOISE_PATTERN_XK = 11
|
||||
|
||||
uint16Size = 2 // uint16 takes 2 bytes
|
||||
MaxPayloadSize = 65537
|
||||
)
|
||||
|
||||
var ciphers = map[byte]noise.CipherFunc{
|
||||
NOISE_CIPHER_CHACHAPOLY: noise.CipherChaChaPoly,
|
||||
NOISE_CIPHER_AESGCM: noise.CipherAESGCM,
|
||||
}
|
||||
|
||||
var hashes = map[byte]noise.HashFunc{
|
||||
NOISE_HASH_SHA256: noise.HashSHA256,
|
||||
}
|
||||
|
||||
var patterns = map[byte]noise.HandshakePattern{
|
||||
NOISE_PATTERN_XK: noise.HandshakeXK,
|
||||
}
|
||||
|
||||
func initNegotiationData(negotiationData []byte) []byte {
|
||||
if negotiationData != nil {
|
||||
return negotiationData
|
||||
}
|
||||
negotiationData = make([]byte, 6)
|
||||
binary.BigEndian.PutUint16(negotiationData, 1) // version
|
||||
negotiationData[2] = NOISE_DH_CURVE25519
|
||||
negotiationData[3] = NOISE_CIPHER_CHACHAPOLY
|
||||
negotiationData[4] = NOISE_HASH_SHA256
|
||||
return negotiationData
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
)
|
||||
|
||||
type NoiseListener struct {
|
||||
Noise
|
||||
net.Listener
|
||||
sync.Mutex
|
||||
lock bool
|
||||
}
|
||||
|
||||
// Addr implements net.Listener.
|
||||
func (ns *NoiseListener) Addr() net.Addr {
|
||||
return ns.Noise.Addr()
|
||||
}
|
||||
|
||||
// Close implements net.Listener.
|
||||
func (ns *NoiseListener) Close() error {
|
||||
return ns.Listener.Close()
|
||||
}
|
||||
|
||||
// Accept implements net.Listener.
|
||||
func (ns *NoiseListener) Accept() (net.Conn, error) {
|
||||
cfg := ns.Noise
|
||||
cfg.Initiator = false
|
||||
accept, err := ns.Listener.Accept()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hs, err := noise.NewHandshakeState(ns.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg.HandshakeState = hs
|
||||
return &NoiseConn{
|
||||
Noise: cfg,
|
||||
Conn: accept,
|
||||
}, nil
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_address"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Noise obfuscation functions used in I2P NTCP2 and SSU2 Handshakes,
|
||||
// including obfuscating the ephemeral keys with a known key and IV found
|
||||
// in the netDb.
|
||||
func AESDeObfuscateEphemeralKeys(cipherText string, config noise.Config, bob router_address.RouterAddress) ([]byte, error) {
|
||||
bobsStaticKey, err := bob.StaticKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bobsInitializatonVector, err := bob.InitializationVector()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.WithFields(
|
||||
log.Fields{
|
||||
"at": "(noise) AESObfuscateEphemeralKeys",
|
||||
}).Debugf("getting ready to deobfuscate our bob's ephemeral keys with bob's static key %s and IV %s", bobsStaticKey, bobsInitializatonVector)
|
||||
deobfuscate, err := hex.DecodeString(cipherText)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block, err := aes.NewCipher(bobsStaticKey[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mode := cipher.NewCBCDecrypter(block, bobsInitializatonVector[:])
|
||||
mode.CryptBlocks([]byte(deobfuscate), []byte(deobfuscate))
|
||||
return deobfuscate, nil
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NoisePacketConn struct {
|
||||
*Noise
|
||||
// this is always a actually a PacketConn
|
||||
net.Conn
|
||||
}
|
||||
|
||||
// Read implements net.Conn.
|
||||
func (*NoisePacketConn) Read(b []byte) (n int, err error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// RemoteAddr implements net.Conn.
|
||||
func (n *NoisePacketConn) RemoteAddr() net.Addr {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// Write implements net.Conn.
|
||||
func (*NoisePacketConn) Write(b []byte) (n int, err error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// Close implements net.PacketConn.
|
||||
// Subtle: this method shadows the method (Conn).Close of NoisePacketConn.Conn.
|
||||
func (n *NoisePacketConn) Close() error {
|
||||
return n.Conn.Close()
|
||||
}
|
||||
|
||||
// LocalAddr implements net.PacketConn.
|
||||
func (n *NoisePacketConn) LocalAddr() net.Addr {
|
||||
return &n.Noise.RouterInfo
|
||||
}
|
||||
|
||||
// ReadFrom implements net.PacketConn.
|
||||
func (*NoisePacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// SetDeadline implements net.PacketConn.
|
||||
// Subtle: this method shadows the method (PacketConn).SetDeadline of NoisePacketConn.PacketConn.
|
||||
func (n *NoisePacketConn) SetDeadline(t time.Time) error {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// SetReadDeadline implements net.PacketConn.
|
||||
// Subtle: this method shadows the method (PacketConn).SetReadDeadline of NoisePacketConn.PacketConn.
|
||||
func (n *NoisePacketConn) SetReadDeadline(t time.Time) error {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// SetWriteDeadline implements net.PacketConn.
|
||||
// Subtle: this method shadows the method (PacketConn).SetWriteDeadline of NoisePacketConn.PacketConn.
|
||||
func (n *NoisePacketConn) SetWriteDeadline(t time.Time) error {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// WriteTo implements net.PacketConn.
|
||||
func (*NoisePacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
panic("unimplemented")
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestServer(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEstablishment(t *testing.T) {
|
||||
}
|
94
lib/transport/noise/outgoing_handshake.go
Normal file
94
lib/transport/noise/outgoing_handshake.go
Normal file
@ -0,0 +1,94 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"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")
|
||||
|
||||
negData, msg, state, err := ComposeInitiatorHandshakeMessage(c.HandKey, nil, nil, nil)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to compose initiator handshake message")
|
||||
return err
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"negData_length": len(negData),
|
||||
"msg_length": len(msg),
|
||||
}).Debug("Initiator handshake message composed")
|
||||
|
||||
if _, err = c.Write(negData); err != nil {
|
||||
log.WithError(err).Error("Failed to write negotiation data")
|
||||
return err
|
||||
}
|
||||
log.Debug("Negotiation data written successfully")
|
||||
|
||||
if _, err = c.Write(msg); err != nil {
|
||||
log.WithError(err).Error("Failed to write handshake message")
|
||||
return err
|
||||
}
|
||||
log.Debug("Handshake message written successfully")
|
||||
log.WithField("state", state).Debug("Handshake state after message write")
|
||||
log.Println(state)
|
||||
c.handshakeComplete = true
|
||||
log.Debug("Outgoing handshake completed successfully")
|
||||
return nil
|
||||
}
|
125
lib/transport/noise/read_session.go
Normal file
125
lib/transport/noise/read_session.go
Normal file
@ -0,0 +1,125 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (c *NoiseSession) Read(b []byte) (int, error) {
|
||||
log.WithField("buffer_length", len(b)).Debug("Starting NoiseSession Read")
|
||||
// interlock with Close below
|
||||
for {
|
||||
x := atomic.LoadInt32(&c.activeCall)
|
||||
if x&1 != 0 {
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(NoiseSession) Read",
|
||||
"reason": "session is closed",
|
||||
}).Error("session is closed")
|
||||
return 0, errors.New("session is closed")
|
||||
}
|
||||
if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) {
|
||||
defer atomic.AddInt32(&c.activeCall, -2)
|
||||
break
|
||||
}
|
||||
log.Debug("NoiseSession Read: retrying atomic operation")
|
||||
}
|
||||
if !c.handshakeComplete {
|
||||
log.Debug("NoiseSession Read: handshake not complete, running incoming handshake")
|
||||
if err := c.RunIncomingHandshake(); err != nil {
|
||||
log.WithError(err).Error("NoiseSession Read: failed to run incoming handshake")
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
c.Mutex.Lock()
|
||||
defer c.Mutex.Unlock()
|
||||
if !c.handshakeComplete {
|
||||
log.Error("NoiseSession Read: internal error - handshake still not complete after running")
|
||||
return 0, errors.New("internal error")
|
||||
}
|
||||
n, err := c.readPacketLocked(b)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("NoiseSession Read: failed to read packet")
|
||||
} else {
|
||||
log.WithField("bytes_read", n).Debug("NoiseSession Read: successfully read packet")
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *NoiseSession) decryptPacket(data []byte) (int, []byte, error) {
|
||||
log.WithField("data_length", len(data)).Debug("Starting packet decryption")
|
||||
|
||||
if c.CipherState == nil {
|
||||
log.Error("Packet decryption: CipherState is nil")
|
||||
return 0, nil, errors.New("CipherState is nil")
|
||||
}
|
||||
// Decrypt
|
||||
decryptedData, err := c.CipherState.Decrypt(nil, nil, data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Packet decryption: failed to decrypt data")
|
||||
return 0, nil, err
|
||||
}
|
||||
m := len(decryptedData)
|
||||
log.WithField("decrypted_length", m).Debug("Packet decryption: successfully decrypted data")
|
||||
return m, decryptedData, nil
|
||||
/*packet := c.InitializePacket()
|
||||
maxPayloadSize := c.maxPayloadSizeForRead(packet)
|
||||
if m > int(maxPayloadSize) {
|
||||
m = int(maxPayloadSize)
|
||||
}
|
||||
if c.CipherState != nil {
|
||||
////fmt.Println("writing encrypted packet:", m)
|
||||
packet.reserve(uint16Size + uint16Size + m + macSize)
|
||||
packet.resize(uint16Size + uint16Size + m)
|
||||
copy(packet.data[uint16Size+uint16Size:], data[:m])
|
||||
binary.BigEndian.PutUint16(packet.data[uint16Size:], uint16(m))
|
||||
//fmt.Println("encrypt size", uint16(m))
|
||||
} else {
|
||||
packet.resize(len(packet.data) + len(data))
|
||||
copy(packet.data[uint16Size:len(packet.data)], data[:m])
|
||||
binary.BigEndian.PutUint16(packet.data, uint16(len(data)))
|
||||
}
|
||||
b := c.encryptIfNeeded(packet)*/
|
||||
//c.freeBlock(packet)
|
||||
}
|
||||
|
||||
func (c *NoiseSession) readPacketLocked(data []byte) (int, error) {
|
||||
log.WithField("data_length", len(data)).Debug("Starting readPacketLocked")
|
||||
|
||||
var n int
|
||||
if len(data) == 0 { // special case to answer when everything is ok during handshake
|
||||
log.Debug("readPacketLocked: special case - reading 2 bytes during handshake")
|
||||
if _, err := c.Conn.Read(make([]byte, 2)); err != nil {
|
||||
log.WithError(err).Error("readPacketLocked: failed to read 2 bytes during handshake")
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
for len(data) > 0 {
|
||||
m, b, err := c.encryptPacket(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("readPacketLocked: failed to encrypt packet")
|
||||
return 0, err
|
||||
}
|
||||
/*
|
||||
if n, err := c.Conn.Read(b); err != nil {
|
||||
return n, err
|
||||
} else {
|
||||
n += m
|
||||
data = data[m:]
|
||||
}
|
||||
*/
|
||||
n, err := c.Conn.Read(b)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("bytes_read (aka n)", n).Error("readPacketLocked: failed to read from connection")
|
||||
return n, err
|
||||
}
|
||||
n += m
|
||||
data = data[m:]
|
||||
log.WithFields(logrus.Fields{
|
||||
"bytes_read": n,
|
||||
"remaining_data": len(data),
|
||||
}).Debug("readPacketLocked: read packet chunk")
|
||||
}
|
||||
return n, nil
|
||||
}
|
139
lib/transport/noise/session.go
Normal file
139
lib/transport/noise/session.go
Normal file
@ -0,0 +1,139 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
cb "github.com/emirpasic/gods/queues/circularbuffer"
|
||||
"github.com/flynn/noise"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_info"
|
||||
"github.com/go-i2p/go-i2p/lib/transport"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// RemoteAddr implements net.Conn
|
||||
func (noise_session *NoiseSession) RemoteAddr() net.Addr {
|
||||
log.WithField("remote_addr", noise_session.RouterInfo.String()).Debug("Getting RemoteAddr")
|
||||
return &noise_session.RouterInfo
|
||||
}
|
||||
|
||||
// SetDeadline implements net.Conn
|
||||
func (noise_session *NoiseSession) SetDeadline(t time.Time) error {
|
||||
log.WithField("deadline", t).Debug("Setting deadline")
|
||||
return noise_session.Conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
// SetReadDeadline implements net.Conn
|
||||
func (noise_session *NoiseSession) SetReadDeadline(t time.Time) error {
|
||||
log.WithField("read_deadline", t).Debug("Setting read deadline")
|
||||
return noise_session.Conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
// SetWriteDeadline implements net.Conn
|
||||
func (noise_session *NoiseSession) SetWriteDeadline(t time.Time) error {
|
||||
log.WithField("write_deadline", t).Debug("Setting write deadline")
|
||||
return noise_session.Conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
var (
|
||||
exampleNoiseSession transport.TransportSession = &NoiseSession{}
|
||||
ExampleNoiseSession net.Conn = exampleNoiseSession.(*NoiseSession)
|
||||
)
|
||||
|
||||
func (s *NoiseSession) LocalAddr() net.Addr {
|
||||
localAddr := s.Conn.LocalAddr()
|
||||
log.WithField("local_addr", localAddr.String()).Debug("Getting LocalAddr")
|
||||
return s.Conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (s *NoiseSession) Close() error {
|
||||
log.Debug("Closing NoiseSession")
|
||||
s.SendQueue.Clear()
|
||||
s.RecvQueue.Clear()
|
||||
log.Debug("SendQueue and RecvQueue cleared")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *NoiseSession) processCallback(publicKey []byte, payload []byte) error {
|
||||
log.WithFields(logrus.Fields{
|
||||
"public_key_length": len(publicKey),
|
||||
"payload_length": len(payload),
|
||||
}).Debug("Processing callback")
|
||||
|
||||
if c.VerifyCallback == nil {
|
||||
log.Debug("VerifyCallback is nil, skipping verification")
|
||||
return nil
|
||||
}
|
||||
err := c.VerifyCallback(publicKey, payload)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("VerifyCallback failed")
|
||||
} else {
|
||||
log.Debug("VerifyCallback succeeded")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// newBlock allocates a new packet, from hc's free list if possible.
|
||||
func newBlock() []byte {
|
||||
// return make([]byte, MaxPayloadSize)
|
||||
block := make([]byte, MaxPayloadSize)
|
||||
log.WithField("block_size", MaxPayloadSize).Debug("Created new block")
|
||||
return block
|
||||
}
|
||||
|
||||
type VerifyCallbackFunc func(publicKey []byte, data []byte) error
|
||||
|
||||
func NewNoiseTransportSession(ri router_info.RouterInfo) (transport.TransportSession, error) {
|
||||
log.WithField("router_info", ri.String()).Debug("Creating new NoiseTransportSession")
|
||||
// socket, err := DialNoise("noise", ri)
|
||||
for _, addr := range ri.RouterAddresses() {
|
||||
log.WithField("address", string(addr.Bytes())).Debug("Attempting to dial")
|
||||
socket, err := net.Dial("tcp", string(addr.Bytes()))
|
||||
if err != nil {
|
||||
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),
|
||||
RouterInfo: ri,
|
||||
Conn: socket,
|
||||
}
|
||||
log.WithField("local_addr", socket.LocalAddr().String()).Debug("NoiseTransportSession created successfully")
|
||||
return session, nil
|
||||
}
|
||||
log.Error("Failed to create NoiseTransportSession, all addresses failed")
|
||||
return nil, fmt.Errorf("Transport constructor error")
|
||||
}
|
1
lib/transport/noise/session_test.go
Normal file
1
lib/transport/noise/session_test.go
Normal file
@ -0,0 +1 @@
|
||||
package noise
|
179
lib/transport/noise/transport.go
Normal file
179
lib/transport/noise/transport.go
Normal file
@ -0,0 +1,179 @@
|
||||
package noise
|
||||
|
||||
/**
|
||||
* NoiseTransport is an unused transport which is used only for testing the
|
||||
* transport interfaces. I2P adds obfuscation to NOISE with the NTCP2 protocol
|
||||
* which is one of the transports which we use in practice.
|
||||
**/
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"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"
|
||||
"github.com/go-i2p/go-i2p/lib/transport"
|
||||
)
|
||||
|
||||
type NoiseTransport struct {
|
||||
sync.Mutex
|
||||
router_identity.RouterIdentity
|
||||
*noise.CipherState
|
||||
Listener net.Listener
|
||||
peerConnections map[data.Hash]transport.TransportSession
|
||||
}
|
||||
|
||||
func (noopt *NoiseTransport) Compatible(routerInfo router_info.RouterInfo) bool {
|
||||
// TODO implement
|
||||
// panic("implement me")
|
||||
log.Warn("func (noopt *NoiseTransport) Compatible(routerInfo router_info.RouterInfo) is not implemented!")
|
||||
return true
|
||||
}
|
||||
|
||||
var exampleNoiseTransport transport.Transport = &NoiseTransport{}
|
||||
|
||||
// ExampleNoiseListener is not a real Noise Listener, do not use it.
|
||||
// It is exported so that it can be confirmed that the transport
|
||||
// implements net.Listener
|
||||
var ExampleNoiseListener net.Listener = exampleNoiseTransport
|
||||
|
||||
// Accept a connection on a listening socket.
|
||||
func (noopt *NoiseTransport) Accept() (net.Conn, error) {
|
||||
log.Debug("NoiseTransport: Accepting new connection")
|
||||
// return noopt.Listener.Accept()
|
||||
conn, err := noopt.Listener.Accept()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("NoiseTransport: Failed to accept connection")
|
||||
} else {
|
||||
log.WithField("remote_addr", conn.RemoteAddr().String()).Debug("NoiseTransport: Accepted new connection")
|
||||
}
|
||||
return conn, err
|
||||
}
|
||||
|
||||
// Addr of the transport, for now this is returning the IP:Port the transport is listening on,
|
||||
// but this might actually be the router identity
|
||||
func (noopt *NoiseTransport) Addr() net.Addr {
|
||||
// return noopt.Listener.Addr()
|
||||
addr := noopt.Listener.Addr()
|
||||
log.WithField("addr", addr.String()).Debug("NoiseTransport: Returning address")
|
||||
return addr
|
||||
}
|
||||
|
||||
// Name of the transport TYPE, in this case `noise`
|
||||
func (noopt *NoiseTransport) Name() string {
|
||||
return "noise"
|
||||
}
|
||||
|
||||
// SetIdentity will set the router identity for this transport.
|
||||
// will bind if the underlying socket is not already
|
||||
// if the underlying socket is already bound update the RouterIdentity
|
||||
// returns any errors that happen if they do
|
||||
func (noopt *NoiseTransport) SetIdentity(ident router_identity.RouterIdentity) (err error) {
|
||||
log.WithField("identity", ident).Debug("NoiseTransport: Setting identity")
|
||||
noopt.RouterIdentity = ident
|
||||
if noopt.Listener == nil {
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(NoiseTransport) SetIdentity",
|
||||
"reason": "network socket is null",
|
||||
}).Error("network socket is null")
|
||||
err = errors.New("network socket is null")
|
||||
return
|
||||
}
|
||||
log.Debug("NoiseTransport: Identity set successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Obtain a transport session with a router given its RouterInfo.
|
||||
// If a session with this router is NOT already made attempt to create one and block until made or until an error happens
|
||||
// returns an established TransportSession and nil on success
|
||||
// returns nil and an error on error
|
||||
func (noopt *NoiseTransport) GetSession(routerInfo router_info.RouterInfo) (transport.TransportSession, error) {
|
||||
hash := routerInfo.IdentHash()
|
||||
log.WithField("hash", hash).Debug("NoiseTransport: Getting session")
|
||||
if len(hash) == 0 {
|
||||
log.Error("NoiseTransport: RouterInfo has no IdentityHash")
|
||||
return nil, errors.New("NoiseTransport: GetSession: RouterInfo has no IdentityHash")
|
||||
}
|
||||
if t, ok := noopt.peerConnections[hash]; ok {
|
||||
log.Debug("NoiseTransport: Existing session found")
|
||||
return t, nil
|
||||
}
|
||||
log.Debug("NoiseTransport: Creating new session")
|
||||
var err error
|
||||
if noopt.peerConnections[hash], err = NewNoiseTransportSession(routerInfo); err != nil {
|
||||
log.WithError(err).Error("NoiseTransport: Failed to create new session")
|
||||
return noopt.peerConnections[hash], err
|
||||
}
|
||||
log.Debug("NoiseTransport: New session created successfully")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *NoiseTransport) getSession(routerInfo router_info.RouterInfo) (transport.TransportSession, error) {
|
||||
log.WithField("router_info", routerInfo.String()).Debug("NoiseTransport: Getting session (internal)")
|
||||
session, err := c.GetSession(routerInfo)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("NoiseTransport: Failed to get session")
|
||||
return nil, err
|
||||
}
|
||||
for {
|
||||
if session.(*NoiseSession).handshakeComplete {
|
||||
log.Debug("NoiseTransport: Handshake complete")
|
||||
return nil, nil
|
||||
}
|
||||
if session.(*NoiseSession).Cond == nil {
|
||||
log.Debug("NoiseTransport: No condition variable, breaking")
|
||||
break
|
||||
}
|
||||
log.Debug("NoiseTransport: Waiting for handshake to complete")
|
||||
session.(*NoiseSession).Cond.Wait()
|
||||
}
|
||||
log.Debug("NoiseTransport: Returning session")
|
||||
return session, nil
|
||||
}
|
||||
|
||||
// Compatable return true if a routerInfo is compatable with this transport
|
||||
func (noopt *NoiseTransport) Compatable(routerInfo router_info.RouterInfo) bool {
|
||||
_, ok := noopt.peerConnections[routerInfo.IdentHash()]
|
||||
log.WithFields(logrus.Fields{
|
||||
"router_info": routerInfo.String(),
|
||||
"compatible": ok,
|
||||
}).Debug("NoiseTransport: Checking compatibility")
|
||||
return ok
|
||||
}
|
||||
|
||||
// close the transport cleanly
|
||||
// blocks until done
|
||||
// returns an error if one happens
|
||||
func (noopt *NoiseTransport) Close() error {
|
||||
log.Debug("NoiseTransport: Closing transport")
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewNoiseTransport create a NoiseTransport using a supplied net.Listener
|
||||
func NewNoiseTransport(netSocket net.Listener) *NoiseTransport {
|
||||
log.WithField("listener_addr", netSocket.Addr().String()).Debug("Creating new NoiseTransport")
|
||||
return &NoiseTransport{
|
||||
peerConnections: make(map[data.Hash]transport.TransportSession),
|
||||
Listener: netSocket,
|
||||
}
|
||||
}
|
||||
|
||||
// NewNoiseTransportSocket creates a Noise transport socket with a random
|
||||
// host and port.
|
||||
func NewNoiseTransportSocket() (*NoiseTransport, error) {
|
||||
log.Debug("Creating new NoiseTransportSocket")
|
||||
netSocket, err := net.Listen("tcp", "")
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create listener for NoiseTransportSocket")
|
||||
return nil, err
|
||||
}
|
||||
// return NewNoiseTransport(netSocket), nil
|
||||
_transport := NewNoiseTransport(netSocket)
|
||||
log.WithField("addr", netSocket.Addr().String()).Debug("Created new NoiseTransportSocket")
|
||||
return _transport, nil
|
||||
}
|
33
lib/transport/noise/transport_test.go
Normal file
33
lib/transport/noise/transport_test.go
Normal file
@ -0,0 +1,33 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTransport(t *testing.T) {
|
||||
ln, err := net.Listen("tcp", ":42069")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
nt := NewNoiseTransport(ln)
|
||||
go func() {
|
||||
for {
|
||||
conn, err := nt.Accept()
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
_, err = conn.Write([]byte("World"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
lnn, err := net.Listen("tcp", ":42070")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
ntt := NewNoiseTransport(lnn)
|
||||
t.Log(ntt.Name())
|
||||
// ntt.GetSession()
|
||||
}
|
133
lib/transport/noise/write_session.go
Normal file
133
lib/transport/noise/write_session.go
Normal file
@ -0,0 +1,133 @@
|
||||
package noise
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (c *NoiseSession) Write(b []byte) (int, error) {
|
||||
log.WithField("data_length", len(b)).Debug("NoiseSession: Starting Write operation")
|
||||
// interlock with Close below
|
||||
for {
|
||||
x := atomic.LoadInt32(&c.activeCall)
|
||||
if x&1 != 0 {
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(NoiseSession) Write",
|
||||
"reason": "session is closed",
|
||||
}).Error("session is closed")
|
||||
return 0, errors.New("session is closed")
|
||||
}
|
||||
if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) {
|
||||
defer atomic.AddInt32(&c.activeCall, -2)
|
||||
break
|
||||
}
|
||||
log.Debug("NoiseSession: Write - retrying atomic operation")
|
||||
}
|
||||
if !c.handshakeComplete {
|
||||
log.Debug("NoiseSession: Write - handshake not complete, running outgoing handshake")
|
||||
if err := c.RunOutgoingHandshake(); err != nil {
|
||||
log.WithError(err).Error("NoiseSession: Write - failed to run outgoing handshake")
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
c.Mutex.Lock()
|
||||
defer c.Mutex.Unlock()
|
||||
if !c.handshakeComplete {
|
||||
log.Error("NoiseSession: Write - internal error, handshake still not complete")
|
||||
return 0, errors.New("internal error")
|
||||
}
|
||||
n, err := c.writePacketLocked(b)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("NoiseSession: Write - failed to write packet")
|
||||
} else {
|
||||
log.WithField("bytes_written", n).Debug("NoiseSession: Write - successfully wrote packet")
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *NoiseSession) encryptPacket(data []byte) (int, []byte, error) {
|
||||
log.WithField("data_length", len(data)).Debug("NoiseSession: Starting packet encryption")
|
||||
|
||||
m := len(data)
|
||||
if c.CipherState == nil {
|
||||
log.Error("NoiseSession: encryptPacket - CipherState is nil")
|
||||
return 0, nil, errors.New("CipherState is nil")
|
||||
}
|
||||
|
||||
// Encrypt the data
|
||||
encryptedData, err := c.CipherState.Encrypt(nil, nil, data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("NoiseSession: encryptPacket - failed to encrypt data")
|
||||
return 0, nil, fmt.Errorf("failed to encrypt: '%w'", err)
|
||||
}
|
||||
// m := len(encryptedData)
|
||||
|
||||
lengthPrefix := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(lengthPrefix, uint16(len(encryptedData)))
|
||||
|
||||
// Append encr data to prefix
|
||||
packet := append(lengthPrefix, encryptedData...)
|
||||
log.WithFields(logrus.Fields{
|
||||
"original_length": m,
|
||||
"encrypted_length": len(encryptedData),
|
||||
"packet_length": len(packet),
|
||||
}).Debug("NoiseSession: encryptPacket - packet encrypted successfully")
|
||||
return m, packet, nil
|
||||
/*packet := c.InitializePacket()
|
||||
maxPayloadSize := c.maxPayloadSizeForWrite(packet)
|
||||
if m > int(maxPayloadSize) {
|
||||
m = int(maxPayloadSize)
|
||||
}
|
||||
if c.CipherState != nil {
|
||||
////fmt.Println("writing encrypted packet:", m)
|
||||
packet.reserve(uint16Size + uint16Size + m + macSize)
|
||||
packet.resize(uint16Size + uint16Size + m)
|
||||
copy(packet.data[uint16Size+uint16Size:], data[:m])
|
||||
binary.BigEndian.PutUint16(packet.data[uint16Size:], uint16(m))
|
||||
//fmt.Println("encrypt size", uint16(m))
|
||||
} else {
|
||||
packet.resize(len(packet.data) + len(data))
|
||||
copy(packet.data[uint16Size:len(packet.data)], data[:m])
|
||||
binary.BigEndian.PutUint16(packet.data, uint16(len(data)))
|
||||
}
|
||||
b := c.encryptIfNeeded(packet)*/
|
||||
//c.freeBlock(packet)
|
||||
}
|
||||
|
||||
func (c *NoiseSession) writePacketLocked(data []byte) (int, error) {
|
||||
log.WithField("data_length", len(data)).Debug("NoiseSession: Starting writePacketLocked")
|
||||
|
||||
var n int
|
||||
if len(data) == 0 { // special case to answer when everything is ok during handshake
|
||||
log.Debug("NoiseSession: writePacketLocked - special case, writing 2 empty bytes")
|
||||
if _, err := c.Conn.Write(make([]byte, 2)); err != nil {
|
||||
log.WithError(err).Error("NoiseSession: writePacketLocked - failed to write empty bytes")
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
for len(data) > 0 {
|
||||
m, b, err := c.encryptPacket(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("NoiseSession: writePacketLocked - failed to encrypt packet")
|
||||
return 0, err
|
||||
}
|
||||
if n, err := c.Conn.Write(b); err != nil {
|
||||
log.WithError(err).WithField("bytes_written", n).Error("NoiseSession: writePacketLocked - failed to write to connection")
|
||||
return n, err
|
||||
} else {
|
||||
n += m
|
||||
data = data[m:]
|
||||
log.WithFields(logrus.Fields{
|
||||
"bytes_written": n,
|
||||
"remaining_data": len(data),
|
||||
}).Debug("NoiseSession: writePacketLocked - wrote packet chunk")
|
||||
}
|
||||
}
|
||||
|
||||
log.WithField("total_bytes_written", n).Debug("NoiseSession: writePacketLocked - completed writing all packets")
|
||||
return n, nil
|
||||
}
|
34
lib/transport/ntcp/constants.go
Normal file
34
lib/transport/ntcp/constants.go
Normal file
@ -0,0 +1,34 @@
|
||||
package ntcp
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/flynn/noise"
|
||||
)
|
||||
|
||||
const (
|
||||
NOISE_DH_CURVE25519 = 1
|
||||
|
||||
NOISE_CIPHER_CHACHAPOLY = 1
|
||||
NOISE_CIPHER_AESGCM = 2
|
||||
|
||||
NOISE_HASH_SHA256 = 3
|
||||
|
||||
NOISE_PATTERN_XK = 11
|
||||
|
||||
uint16Size = 2 // uint16 takes 2 bytes
|
||||
MaxPayloadSize = math.MaxUint16 - 16 /*mac size*/ - uint16Size /*data len*/
|
||||
)
|
||||
|
||||
var ciphers = map[byte]noise.CipherFunc{
|
||||
NOISE_CIPHER_CHACHAPOLY: noise.CipherChaChaPoly,
|
||||
NOISE_CIPHER_AESGCM: noise.CipherAESGCM,
|
||||
}
|
||||
|
||||
var hashes = map[byte]noise.HashFunc{
|
||||
NOISE_HASH_SHA256: noise.HashSHA256,
|
||||
}
|
||||
|
||||
var patterns = map[byte]noise.HandshakePattern{
|
||||
NOISE_PATTERN_XK: noise.HandshakeXK,
|
||||
}
|
61
lib/transport/ntcp/obfs.go
Normal file
61
lib/transport/ntcp/obfs.go
Normal file
@ -0,0 +1,61 @@
|
||||
package ntcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
)
|
||||
|
||||
// ObfuscateEphemeralKey encrypts the ephemeral public key in the message using AES-256-CBC without padding
|
||||
func ObfuscateEphemeralKey(message []byte, aesKey *crypto.AESSymmetricKey) ([]byte, error) {
|
||||
if len(message) < 32 {
|
||||
return nil, fmt.Errorf("message is too short to contain ephemeral public key")
|
||||
}
|
||||
|
||||
// Extract the ephemeral public key (first 32 bytes)
|
||||
ephemeralPubKey := message[:32]
|
||||
|
||||
// Create AES encrypter
|
||||
encrypter := &crypto.AESSymmetricEncrypter{
|
||||
Key: aesKey.Key,
|
||||
IV: aesKey.IV,
|
||||
}
|
||||
|
||||
// Encrypt the ephemeral public key without padding
|
||||
encryptedKey, err := encrypter.EncryptNoPadding(ephemeralPubKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Replace the ephemeral public key in the message with the encrypted key
|
||||
obfuscatedMessage := append(encryptedKey, message[32:]...)
|
||||
|
||||
return obfuscatedMessage, nil
|
||||
}
|
||||
|
||||
// DeobfuscateEphemeralKey decrypts the ephemeral public key in the message using AES-256-CBC without padding
|
||||
func DeobfuscateEphemeralKey(message []byte, aesKey *crypto.AESSymmetricKey) ([]byte, error) {
|
||||
if len(message) < 32 {
|
||||
return nil, fmt.Errorf("message is too short to contain ephemeral public key")
|
||||
}
|
||||
|
||||
// Extract the encrypted ephemeral public key (first 32 bytes)
|
||||
encryptedKey := message[:32]
|
||||
|
||||
// Create AES decrypter
|
||||
decrypter := &crypto.AESSymmetricDecrypter{
|
||||
Key: aesKey.Key,
|
||||
IV: aesKey.IV,
|
||||
}
|
||||
|
||||
// Decrypt the ephemeral public key without padding
|
||||
decryptedKey, err := decrypter.DecryptNoPadding(encryptedKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Replace the encrypted ephemeral key in the message with the decrypted key
|
||||
deobfuscatedMessage := append(decryptedKey, message[32:]...)
|
||||
|
||||
return deobfuscatedMessage, nil
|
||||
}
|
@ -43,8 +43,8 @@ type Transport interface {
|
||||
// returns nil and an error on error
|
||||
GetSession(routerInfo router_info.RouterInfo) (TransportSession, error)
|
||||
|
||||
// return true if a routerInfo is compatable with this transport
|
||||
Compatable(routerInfo router_info.RouterInfo) bool
|
||||
// return true if a routerInfo is compatible with this transport
|
||||
Compatible(routerInfo router_info.RouterInfo) bool
|
||||
|
||||
// close the transport cleanly
|
||||
// blocks until done
|
||||
|
@ -5,9 +5,12 @@ import (
|
||||
"errors"
|
||||
|
||||
common "github.com/go-i2p/go-i2p/lib/common/data"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
/*
|
||||
I2P First Fragment Delivery Instructions
|
||||
https://geti2p.net/spec/tunnel-message#struct-tunnelmessagedeliveryinstructions
|
||||
@ -152,6 +155,7 @@ type DeliveryInstructions []byte
|
||||
|
||||
// Return if the DeliveryInstructions are of type FIRST_FRAGMENT or FOLLOW_ON_FRAGMENT.
|
||||
func (delivery_instructions DeliveryInstructions) Type() (int, error) {
|
||||
log.Debug("Determining DeliveryInstructions type")
|
||||
if len(delivery_instructions) >= 1 {
|
||||
/*
|
||||
Check if the 7 bit of the Delivery Instructions
|
||||
@ -169,18 +173,23 @@ func (delivery_instructions DeliveryInstructions) Type() (int, error) {
|
||||
fragment or a complete fragment
|
||||
*/
|
||||
if (delivery_instructions[0] & 0x08) == 0x08 {
|
||||
log.Debug("DeliveryInstructions type: FOLLOW_ON_FRAGMENT")
|
||||
return FOLLOW_ON_FRAGMENT, nil
|
||||
}
|
||||
log.Debug("DeliveryInstructions type: FIRST_FRAGMENT")
|
||||
return FIRST_FRAGMENT, nil
|
||||
}
|
||||
log.Error("DeliveryInstructions contains no data")
|
||||
return 0, errors.New("DeliveryInstructions contains no data")
|
||||
}
|
||||
|
||||
// Read the integer stored in the 6-1 bits of a FOLLOW_ON_FRAGMENT's flag, indicating
|
||||
// the fragment number.
|
||||
func (delivery_instructions DeliveryInstructions) FragmentNumber() (int, error) {
|
||||
log.Debug("Getting FragmentNumber")
|
||||
di_type, err := delivery_instructions.Type()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get DeliveryInstructions type")
|
||||
return 0, err
|
||||
}
|
||||
/*
|
||||
@ -193,18 +202,26 @@ func (delivery_instructions DeliveryInstructions) FragmentNumber() (int, error)
|
||||
0??????0 >> 1 => Integer(??????)
|
||||
*/
|
||||
if di_type == FOLLOW_ON_FRAGMENT {
|
||||
return common.Integer(
|
||||
[]byte{((delivery_instructions[0] & 0x7e) >> 1)},
|
||||
).Int(), nil
|
||||
/*
|
||||
return common.Integer(
|
||||
[]byte{((delivery_instructions[0] & 0x7e) >> 1)},
|
||||
).Int(), nil
|
||||
*/
|
||||
fragNum := common.Integer([]byte{((delivery_instructions[0] & 0x7e) >> 1)}).Int()
|
||||
log.WithField("fragment_number", fragNum).Debug("FragmentNumber retrieved")
|
||||
return fragNum, nil
|
||||
}
|
||||
log.Error("Fragment Number only exists on FOLLOW_ON_FRAGMENT Delivery Instructions")
|
||||
return 0, errors.New("Fragment Number only exists on FOLLOW_ON_FRAGMENT Delivery Instructions")
|
||||
}
|
||||
|
||||
// Read the value of the 0 bit of a FOLLOW_ON_FRAGMENT, which is set to 1 to indicate the
|
||||
// last fragment.
|
||||
func (delivery_instructions DeliveryInstructions) LastFollowOnFragment() (bool, error) {
|
||||
log.Debug("Checking if this is the LastFollowOnFragment")
|
||||
di_type, err := delivery_instructions.Type()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get DeliveryInstructions type")
|
||||
return false, err
|
||||
}
|
||||
/*
|
||||
@ -217,18 +234,25 @@ func (delivery_instructions DeliveryInstructions) LastFollowOnFragment() (bool,
|
||||
0000000? => n
|
||||
*/
|
||||
if di_type == FOLLOW_ON_FRAGMENT {
|
||||
if delivery_instructions[0]&0x01 == 0x01 {
|
||||
return true, nil
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
/*
|
||||
if delivery_instructions[0]&0x01 == 0x01 {
|
||||
return true, nil
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
*/
|
||||
isLast := delivery_instructions[0]&0x01 == 0x01
|
||||
log.WithField("is_last", isLast).Debug("LastFollowOnFragment status determined")
|
||||
return isLast, nil
|
||||
}
|
||||
log.Error("Last Fragment only exists for FOLLOW_ON_FRAGMENT Delivery Instructions")
|
||||
return false, errors.New("Last Fragment only exists for FOLLOW_ON_FRAGMENT Delivery Instructions")
|
||||
}
|
||||
|
||||
// Return the delivery type for these DeliveryInstructions, can be of type
|
||||
// DT_LOCAL, DT_TUNNEL, DT_ROUTER, or DT_UNUSED.
|
||||
func (delivery_instructions DeliveryInstructions) DeliveryType() (byte, error) {
|
||||
log.Debug("Getting DeliveryType")
|
||||
if len(delivery_instructions) >= 1 {
|
||||
/*
|
||||
Check if the 6-5 bits of the Delivery Instructions
|
||||
@ -240,13 +264,18 @@ func (delivery_instructions DeliveryInstructions) DeliveryType() (byte, error) {
|
||||
---------
|
||||
000?0000 >> 4 => n (DT_* consts)
|
||||
*/
|
||||
return ((delivery_instructions[0] & 0x30) >> 4), nil
|
||||
//return ((delivery_instructions[0] & 0x30) >> 4), nil
|
||||
deliveryType := (delivery_instructions[0] & 0x30) >> 4
|
||||
log.WithField("delivery_type", deliveryType).Debug("DeliveryType retrieved")
|
||||
return deliveryType, nil
|
||||
}
|
||||
log.Error("DeliveryInstructions contains no data")
|
||||
return 0, errors.New("DeliveryInstructions contains no data")
|
||||
}
|
||||
|
||||
// Check if the delay bit is set. This feature in unimplemented in the Java router.
|
||||
func (delivery_instructions DeliveryInstructions) HasDelay() (bool, error) {
|
||||
log.Debug("Checking if DeliveryInstructions has delay")
|
||||
if len(delivery_instructions) >= 1 {
|
||||
/*
|
||||
Check if the 4 bit of the Delivery Instructions
|
||||
@ -266,19 +295,22 @@ func (delivery_instructions DeliveryInstructions) HasDelay() (bool, error) {
|
||||
*/
|
||||
delay := (delivery_instructions[0] & 0x10) == 0x10
|
||||
if delay {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(DeliveryInstructions) HasDelay",
|
||||
"info": "this feature is unimplemented in the Java router",
|
||||
}).Warn("DeliveryInstructions found with delay bit set")
|
||||
}
|
||||
log.WithField("has_delay", delay).Debug("HasDelay status determined")
|
||||
return delay, nil
|
||||
}
|
||||
log.Error("DeliveryInstructions contains no data")
|
||||
return false, errors.New("DeliveryInstructions contains no data")
|
||||
}
|
||||
|
||||
// Returns true if the Delivery Instructions are fragmented or false
|
||||
// if the following data contains the entire message
|
||||
func (delivery_instructions DeliveryInstructions) Fragmented() (bool, error) {
|
||||
log.Debug("Checking if DeliveryInstructions is fragmented")
|
||||
if len(delivery_instructions) >= 1 {
|
||||
/*
|
||||
Check if the 3 bit of the Delivery Instructions
|
||||
@ -295,13 +327,18 @@ func (delivery_instructions DeliveryInstructions) Fragmented() (bool, error) {
|
||||
message is message is not
|
||||
fragmented fragmented
|
||||
*/
|
||||
return ((delivery_instructions[0] & 0x08) == 0x08), nil
|
||||
fragmented := (delivery_instructions[0] & 0x08) == 0x08
|
||||
log.WithField("fragmented", fragmented).Debug("Fragmented status determined")
|
||||
return fragmented, nil
|
||||
// return ((delivery_instructions[0] & 0x08) == 0x08), nil
|
||||
}
|
||||
log.Error("DeliveryInstructions contains no data")
|
||||
return false, errors.New("DeliveryInstructions contains no data")
|
||||
}
|
||||
|
||||
// Check if the extended options bit is set. This feature in unimplemented in the Java router.
|
||||
func (delivery_instructions DeliveryInstructions) HasExtendedOptions() (bool, error) {
|
||||
log.Debug("Checking if DeliveryInstructions has extended options")
|
||||
if len(delivery_instructions) >= 1 {
|
||||
/*
|
||||
Check if the 2 bit of the Delivery Instructions
|
||||
@ -322,28 +359,37 @@ func (delivery_instructions DeliveryInstructions) HasExtendedOptions() (bool, er
|
||||
*/
|
||||
extended_options := (delivery_instructions[0] & 0x04) == 0x04
|
||||
if extended_options {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(DeliveryInstructions) ExtendedOptions",
|
||||
"info": "this feature is unimplemented in the Java router",
|
||||
}).Warn("DeliveryInstructions found with extended_options bit set")
|
||||
}
|
||||
log.WithField("has_extended_options", extended_options).Debug("HasExtendedOptions status determined")
|
||||
return extended_options, nil
|
||||
}
|
||||
log.Error("DeliveryInstructions contains no data")
|
||||
return false, errors.New("DeliveryInstructions contains no data")
|
||||
}
|
||||
|
||||
// Check if the DeliveryInstructions is of type DT_TUNNEL.
|
||||
func (delivery_instructions DeliveryInstructions) HasTunnelID() (bool, error) {
|
||||
log.Debug("Checking if DeliveryInstructions has TunnelID")
|
||||
di_type, err := delivery_instructions.DeliveryType()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get DeliveryType")
|
||||
return false, err
|
||||
}
|
||||
return di_type == DT_TUNNEL, nil
|
||||
// return di_type == DT_TUNNEL, nil
|
||||
hasTunnelID := di_type == DT_TUNNEL
|
||||
log.WithField("has_tunnel_id", hasTunnelID).Debug("HasTunnelID status determined")
|
||||
return hasTunnelID, nil
|
||||
}
|
||||
|
||||
func (delivery_instructions DeliveryInstructions) HasHash() (bool, error) {
|
||||
log.Debug("Checking if DeliveryInstructions has Hash")
|
||||
di_type, err := delivery_instructions.DeliveryType()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get DeliveryType")
|
||||
return false, err
|
||||
}
|
||||
if di_type == DT_TUNNEL || di_type == DT_ROUTER {
|
||||
@ -352,28 +398,37 @@ func (delivery_instructions DeliveryInstructions) HasHash() (bool, error) {
|
||||
min_size += TUNNEL_ID_SIZE
|
||||
}
|
||||
if len(delivery_instructions) < min_size {
|
||||
log.Error("Delivery Instructions indicates hash present but has too little data")
|
||||
return false, errors.New("Delivery Instructions indicates hash present but has too little data")
|
||||
}
|
||||
log.Debug("DeliveryInstructions has Hash")
|
||||
} else {
|
||||
log.Debug("DeliveryInstructions does not have Hash")
|
||||
return false, nil
|
||||
}
|
||||
log.Debug("DeliveryInstructions does not have Hash(?)")
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Return the tunnel ID in this DeliveryInstructions or 0 and an error if the
|
||||
// DeliveryInstructions are not of type DT_TUNNEL.
|
||||
func (delivery_instructions DeliveryInstructions) TunnelID() (tunnel_id uint32, err error) {
|
||||
log.Debug("Getting TunnelID")
|
||||
has_tunnel_id, err := delivery_instructions.HasTunnelID()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to check HasTunnelID")
|
||||
return
|
||||
}
|
||||
if has_tunnel_id {
|
||||
if len(delivery_instructions) >= FLAG_SIZE+TUNNEL_ID_SIZE {
|
||||
tunnel_id = binary.BigEndian.Uint32(delivery_instructions[FLAG_SIZE:TUNNEL_ID_SIZE])
|
||||
log.WithField("tunnel_id", tunnel_id).Debug("TunnelID retrieved")
|
||||
} else {
|
||||
log.Error("DeliveryInstructions are invalid, too little data for Tunnel ID")
|
||||
err = errors.New("DeliveryInstructions are invalid, too little data for Tunnel ID")
|
||||
}
|
||||
} else {
|
||||
log.Error("DeliveryInstructions are not of type DT_TUNNEL")
|
||||
err = errors.New("DeliveryInstructions are not of type DT_TUNNEL")
|
||||
}
|
||||
return
|
||||
@ -384,8 +439,10 @@ func (delivery_instructions DeliveryInstructions) TunnelID() (tunnel_id uint32,
|
||||
// If the type is DT_TUNNEL, hash is the SHA256 of the gateway router, if
|
||||
// the type is DT_ROUTER it is the SHA256 of the router.
|
||||
func (delivery_instructions DeliveryInstructions) Hash() (hash common.Hash, err error) {
|
||||
log.Debug("Getting Hash")
|
||||
delivery_type, err := delivery_instructions.DeliveryType()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get DeliveryType")
|
||||
return
|
||||
}
|
||||
hash_start := FLAG_SIZE
|
||||
@ -395,16 +452,21 @@ func (delivery_instructions DeliveryInstructions) Hash() (hash common.Hash, err
|
||||
hash_end := hash_end + TUNNEL_ID_SIZE
|
||||
if len(delivery_instructions) >= hash_end {
|
||||
copy(hash[:], delivery_instructions[hash_start:hash_end])
|
||||
log.WithField("hash", hash).Debug("Hash retrieved for DT_TUNNEL")
|
||||
} else {
|
||||
log.Error("DeliveryInstructions is invalid, not contain enough data for hash given type DT_TUNNEL")
|
||||
err = errors.New("DeliveryInstructions is invalid, not contain enough data for hash given type DT_TUNNEL")
|
||||
}
|
||||
} else if delivery_type == DT_ROUTER {
|
||||
if len(delivery_instructions) >= hash_end {
|
||||
copy(hash[:], delivery_instructions[hash_start:hash_end])
|
||||
log.WithField("hash", hash).Debug("Hash retrieved for DT_ROUTER")
|
||||
} else {
|
||||
log.Error("DeliveryInstructions is invalid, not contain enough data for hash given type DT_ROUTER")
|
||||
err = errors.New("DeliveryInstructions is invalid, not contain enough data for hash given type DT_ROUTER")
|
||||
}
|
||||
} else {
|
||||
log.Error("No Hash on DeliveryInstructions not of type DT_TUNNEL or DT_ROUTER")
|
||||
err = errors.New("No Hash on DeliveryInstructions not of type DT_TUNNEL or DT_ROUTER")
|
||||
}
|
||||
return
|
||||
@ -412,32 +474,39 @@ func (delivery_instructions DeliveryInstructions) Hash() (hash common.Hash, err
|
||||
|
||||
// Return the DelayFactor if present and any errors encountered parsing the DeliveryInstructions.
|
||||
func (delivery_instructions DeliveryInstructions) Delay() (delay_factor DelayFactor, err error) {
|
||||
log.Debug("Getting Delay")
|
||||
delay, err := delivery_instructions.HasDelay()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to check HasDelay")
|
||||
return
|
||||
}
|
||||
if delay {
|
||||
var di_type byte
|
||||
di_type, err = delivery_instructions.DeliveryType()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get DeliveryType")
|
||||
return
|
||||
}
|
||||
if di_type == DT_TUNNEL {
|
||||
if len(delivery_instructions) >= FLAG_SIZE+TUNNEL_ID_SIZE+HASH_SIZE {
|
||||
delay_factor = DelayFactor(delivery_instructions[FLAG_SIZE+TUNNEL_ID_SIZE+HASH_SIZE])
|
||||
log.WithField("delay_factor", delay_factor).Debug("Delay factor retrieved for DT_TUNNEL")
|
||||
} else {
|
||||
log.Error("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
|
||||
err = errors.New("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
|
||||
return
|
||||
}
|
||||
} else if di_type == DT_ROUTER {
|
||||
if len(delivery_instructions) >= FLAG_SIZE+HASH_SIZE {
|
||||
delay_factor = DelayFactor(delivery_instructions[FLAG_SIZE+HASH_SIZE])
|
||||
log.WithField("delay_factor", delay_factor).Debug("Delay factor retrieved for DT_ROUTER")
|
||||
} else {
|
||||
log.Error("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
|
||||
err = errors.New("DeliveryInstructions is invalid, does not contain enough data for DelayFactor")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(DeliveryInstructions) Delay",
|
||||
}).Warn("Delay not present on DeliveryInstructions not of type DT_TUNNEL or DT_ROUTER")
|
||||
}
|
||||
@ -448,28 +517,36 @@ func (delivery_instructions DeliveryInstructions) Delay() (delay_factor DelayFac
|
||||
// Return the I2NP Message ID or 0 and an error if the data is not available for this
|
||||
// DeliveryInstructions.
|
||||
func (delivery_instructions DeliveryInstructions) MessageID() (msgid uint32, err error) {
|
||||
log.Debug("Getting MessageID")
|
||||
di_type, err := delivery_instructions.Type()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get DeliveryInstructions type")
|
||||
return
|
||||
}
|
||||
if di_type == FOLLOW_ON_FRAGMENT {
|
||||
if len(delivery_instructions) >= 5 {
|
||||
msgid = binary.BigEndian.Uint32(delivery_instructions[1:5])
|
||||
log.WithField("message_id", msgid).Debug("MessageID retrieved for FOLLOW_ON_FRAGMENT")
|
||||
} else {
|
||||
log.Error("DeliveryInstructions are invalid, not enough data for Message ID")
|
||||
err = errors.New("DeliveryInstructions are invalid, not enough data for Message ID")
|
||||
}
|
||||
} else if di_type == FIRST_FRAGMENT {
|
||||
var message_id_index int
|
||||
message_id_index, err = delivery_instructions.message_id_index()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get message_id_index")
|
||||
return
|
||||
}
|
||||
if len(delivery_instructions) >= message_id_index+4 {
|
||||
msgid = binary.BigEndian.Uint32(delivery_instructions[message_id_index : message_id_index+4])
|
||||
log.WithField("message_id", msgid).Debug("MessageID retrieved for FIRST_FRAGMENT")
|
||||
} else {
|
||||
log.Error("DeliveryInstructions are invalid, not enough data for Message ID")
|
||||
err = errors.New("DeliveryInstructions are invalid, not enough data for Message ID")
|
||||
}
|
||||
} else {
|
||||
log.Error("No Message ID for DeliveryInstructions not of type FIRST_FRAGMENT or FOLLOW_ON_FRAGMENT")
|
||||
err = errors.New("No Message ID for DeliveryInstructions not of type FIRST_FRAGMENT or FOLLOW_ON_FRAGMENT")
|
||||
}
|
||||
return
|
||||
@ -478,31 +555,38 @@ func (delivery_instructions DeliveryInstructions) MessageID() (msgid uint32, err
|
||||
// Return the Extended Options data if present, or an error if not present. Extended Options in unimplemented
|
||||
// in the Java router and the presence of extended options will generate a warning.
|
||||
func (delivery_instructions DeliveryInstructions) ExtendedOptions() (data []byte, err error) {
|
||||
log.Debug("Getting ExtendedOptions")
|
||||
ops, err := delivery_instructions.HasExtendedOptions()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to check HasExtendedOptions")
|
||||
return
|
||||
}
|
||||
if ops {
|
||||
var extended_options_index int
|
||||
extended_options_index, err = delivery_instructions.extended_options_index()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get extended_options_index")
|
||||
return
|
||||
}
|
||||
if len(delivery_instructions) < extended_options_index+2 {
|
||||
log.Error("DeliveryInstructions are invalid, length is shorter than required for Extended Options")
|
||||
err = errors.New("DeliveryInstructions are invalid, length is shorter than required for Extended Options")
|
||||
return
|
||||
} else {
|
||||
extended_options_size := common.Integer([]byte{delivery_instructions[extended_options_index]})
|
||||
if len(delivery_instructions) < extended_options_index+1+extended_options_size.Int() {
|
||||
log.Error("DeliveryInstructions are invalid, length is shorter than specified in Extended Options")
|
||||
err = errors.New("DeliveryInstructions are invalid, length is shorter than specified in Extended Options")
|
||||
return
|
||||
} else {
|
||||
data = delivery_instructions[extended_options_index+1 : extended_options_size.Int()]
|
||||
log.WithField("extended_options_length", len(data)).Debug("Extended Options retrieved")
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
log.Error("DeliveryInstruction does not have the ExtendedOptions flag set")
|
||||
err = errors.New("DeliveryInstruction does not have the ExtendedOptions flag set")
|
||||
}
|
||||
return
|
||||
@ -510,28 +594,36 @@ func (delivery_instructions DeliveryInstructions) ExtendedOptions() (data []byte
|
||||
|
||||
// Return the size of the associated I2NP fragment and an error if the data is unavailable.
|
||||
func (delivery_instructions DeliveryInstructions) FragmentSize() (frag_size uint16, err error) {
|
||||
log.Debug("Getting FragmentSize")
|
||||
di_type, err := delivery_instructions.Type()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get DeliveryInstructions type")
|
||||
return
|
||||
}
|
||||
if di_type == FOLLOW_ON_FRAGMENT {
|
||||
if len(delivery_instructions) >= 7 {
|
||||
frag_size = binary.BigEndian.Uint16(delivery_instructions[5:7])
|
||||
log.WithField("fragment_size", frag_size).Debug("FragmentSize retrieved for FOLLOW_ON_FRAGMENT")
|
||||
} else {
|
||||
log.Error("DeliveryInstructions are invalid, not enough data for Fragment Size")
|
||||
err = errors.New("DeliveryInstructions are invalid, not enough data for Fragment Size")
|
||||
}
|
||||
} else if di_type == FIRST_FRAGMENT {
|
||||
var fragment_size_index int
|
||||
fragment_size_index, err = delivery_instructions.fragment_size_index()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get fragment_size_index")
|
||||
return
|
||||
}
|
||||
if len(delivery_instructions) >= fragment_size_index+2 {
|
||||
frag_size = binary.BigEndian.Uint16(delivery_instructions[fragment_size_index : fragment_size_index+2])
|
||||
log.WithField("fragment_size", frag_size).Debug("FragmentSize retrieved for FIRST_FRAGMENT")
|
||||
} else {
|
||||
log.Error("DeliveryInstructions are invalid, not enough data for Fragment Size")
|
||||
err = errors.New("DeliveryInstructions are invalid, not enough data for Fragment Size")
|
||||
}
|
||||
} else {
|
||||
log.Error("No Fragment Size for DeliveryInstructions not of type FIRST_FRAGMENT or FOLLOW_ON_FRAGMENT")
|
||||
err = errors.New("No Fragment Size for DeliveryInstructions not of type FIRST_FRAGMENT or FOLLOW_ON_FRAGMENT")
|
||||
}
|
||||
return
|
||||
@ -539,8 +631,10 @@ func (delivery_instructions DeliveryInstructions) FragmentSize() (frag_size uint
|
||||
|
||||
// Find the correct index for the Message ID in a FIRST_FRAGMENT DeliveryInstructions
|
||||
func (delivery_instructions DeliveryInstructions) message_id_index() (message_id int, err error) {
|
||||
log.Debug("Calculating message_id_index")
|
||||
fragmented, err := delivery_instructions.Fragmented()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to check if DeliveryInstructions are fragmented")
|
||||
return
|
||||
}
|
||||
if fragmented {
|
||||
@ -551,6 +645,7 @@ func (delivery_instructions DeliveryInstructions) message_id_index() (message_id
|
||||
var di_type byte
|
||||
di_type, err = delivery_instructions.DeliveryType()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get DeliveryType")
|
||||
return
|
||||
}
|
||||
if di_type == DT_TUNNEL {
|
||||
@ -563,22 +658,26 @@ func (delivery_instructions DeliveryInstructions) message_id_index() (message_id
|
||||
var delay bool
|
||||
delay, err = delivery_instructions.HasDelay()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to check HasDelay")
|
||||
return
|
||||
}
|
||||
if delay {
|
||||
message_id++
|
||||
}
|
||||
|
||||
log.WithField("message_id_index", message_id).Debug("message_id_index calculated")
|
||||
return message_id, nil
|
||||
} else {
|
||||
log.Error("DeliveryInstruction must be fragmented to have a Message ID")
|
||||
return 0, errors.New("DeliveryInstruction must be fragmented to have a Message ID")
|
||||
}
|
||||
}
|
||||
|
||||
// Find the index of the extended options in this Delivery Instruction, if they exist.
|
||||
func (delivery_instructions DeliveryInstructions) extended_options_index() (extended_options int, err error) {
|
||||
log.Debug("Calculating extended_options_index")
|
||||
ops, err := delivery_instructions.HasExtendedOptions()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to check HasExtendedOptions")
|
||||
return
|
||||
}
|
||||
if ops {
|
||||
@ -589,6 +688,7 @@ func (delivery_instructions DeliveryInstructions) extended_options_index() (exte
|
||||
var di_type byte
|
||||
di_type, err = delivery_instructions.DeliveryType()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get DeliveryType")
|
||||
return
|
||||
}
|
||||
if di_type == DT_TUNNEL {
|
||||
@ -601,6 +701,7 @@ func (delivery_instructions DeliveryInstructions) extended_options_index() (exte
|
||||
var delay bool
|
||||
delay, err = delivery_instructions.HasDelay()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to check HasDelay")
|
||||
return
|
||||
}
|
||||
if delay {
|
||||
@ -613,9 +714,11 @@ func (delivery_instructions DeliveryInstructions) extended_options_index() (exte
|
||||
} else {
|
||||
err = nil
|
||||
}
|
||||
log.WithField("extended_options_index", extended_options).Debug("extended_options_index calculated")
|
||||
return extended_options, nil
|
||||
|
||||
} else {
|
||||
log.Error("DeliveryInstruction does not have the ExtendedOptions flag set")
|
||||
err = errors.New("DeliveryInstruction does not have the ExtendedOptions flag set")
|
||||
}
|
||||
return
|
||||
@ -623,6 +726,7 @@ func (delivery_instructions DeliveryInstructions) extended_options_index() (exte
|
||||
|
||||
// Find the index of the Fragment Size data in this Delivery Instruction.
|
||||
func (delivery_instructions DeliveryInstructions) fragment_size_index() (fragment_size int, err error) {
|
||||
log.Debug("Calculating fragment_size_index")
|
||||
// Start counting after the flags
|
||||
fragment_size = 1
|
||||
|
||||
@ -630,6 +734,7 @@ func (delivery_instructions DeliveryInstructions) fragment_size_index() (fragmen
|
||||
var di_type byte
|
||||
di_type, err = delivery_instructions.DeliveryType()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to get DeliveryType")
|
||||
return
|
||||
}
|
||||
if di_type == DT_TUNNEL {
|
||||
@ -642,6 +747,7 @@ func (delivery_instructions DeliveryInstructions) fragment_size_index() (fragmen
|
||||
var delay bool
|
||||
delay, err = delivery_instructions.HasDelay()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to check HasDelay")
|
||||
return
|
||||
}
|
||||
if delay {
|
||||
@ -661,22 +767,29 @@ func (delivery_instructions DeliveryInstructions) fragment_size_index() (fragmen
|
||||
fragment_size += len(extended_opts) + 1
|
||||
}
|
||||
}
|
||||
log.WithField("fragment_size_index", fragment_size).Debug("fragment_size_index calculated")
|
||||
return fragment_size, nil
|
||||
}
|
||||
|
||||
func maybeAppendTunnelID(data, current []byte) (now []byte, err error) {
|
||||
log.Debug("Attempting to append TunnelID")
|
||||
if has_tunnel_id, _ := DeliveryInstructions(data).HasTunnelID(); has_tunnel_id {
|
||||
_, err = DeliveryInstructions(data).TunnelID()
|
||||
if err == nil {
|
||||
now = append(current, data[1:5]...)
|
||||
log.Debug("TunnelID appended")
|
||||
} else {
|
||||
log.WithError(err).Error("Failed to get TunnelID")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
log.Debug("No TunnelID to append")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func maybeAppendHash(di_flag DeliveryInstructions, data, current []byte) (now []byte, err error) {
|
||||
log.Debug("Attempting to append Hash")
|
||||
delivery_type, _ := di_flag.DeliveryType()
|
||||
if _, err := DeliveryInstructions(data).HasHash(); err == nil {
|
||||
hash_start := 1
|
||||
@ -687,12 +800,16 @@ func maybeAppendHash(di_flag DeliveryInstructions, data, current []byte) (now []
|
||||
}
|
||||
if err == nil {
|
||||
now = append(current, data[hash_start:hash_end]...)
|
||||
log.Debug("Hash appended")
|
||||
}
|
||||
} else {
|
||||
log.Debug("No Hash to append")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func maybeAppendDelay(di_flag DeliveryInstructions, data, current []byte) (now []byte, err error) {
|
||||
log.Debug("Attempting to append Delay")
|
||||
delivery_type, _ := di_flag.DeliveryType()
|
||||
if _, err = DeliveryInstructions(data).HasHash(); err == nil {
|
||||
delay_start := 1
|
||||
@ -704,12 +821,16 @@ func maybeAppendDelay(di_flag DeliveryInstructions, data, current []byte) (now [
|
||||
}
|
||||
if err == nil {
|
||||
now = append(current, data[delay_start])
|
||||
log.Debug("Delay appended")
|
||||
}
|
||||
} else {
|
||||
log.Debug("No Delay to append")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func maybeAppendMessageID(di_flag DeliveryInstructions, di_type int, data, current []byte) (now []byte, err error) {
|
||||
log.Debug("Attempting to append MessageID")
|
||||
if di_type == FIRST_FRAGMENT {
|
||||
if fragmented, _ := di_flag.Fragmented(); fragmented {
|
||||
message_id_index := 1
|
||||
@ -723,47 +844,61 @@ func maybeAppendMessageID(di_flag DeliveryInstructions, di_type int, data, curre
|
||||
message_id_index += 1
|
||||
}
|
||||
if len(data) < message_id_index+4 {
|
||||
log.Error("Data is too short to contain message ID in FIRST_FRAGMENT")
|
||||
err = errors.New("data is too short to contain message ID in FIRST_FRAGMENT")
|
||||
} else {
|
||||
now = append(current, data[message_id_index:message_id_index+4]...)
|
||||
log.Debug("MessageID appended for FIRST_FRAGMENT")
|
||||
}
|
||||
}
|
||||
} else if di_type == FOLLOW_ON_FRAGMENT {
|
||||
if len(data) < 5 {
|
||||
log.Error("Data is too short to contain message ID in FOLLOW_ON_FRAGMENT")
|
||||
err = errors.New("data is too short to contain message ID in FOLLOW_ON_FRAGMENT")
|
||||
} else {
|
||||
now = append(current, data[1:5]...)
|
||||
log.Debug("MessageID appended for FOLLOW_ON_FRAGMENT")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func maybeAppendExtendedOptions(di_flag DeliveryInstructions, data, current []byte) (now []byte, err error) {
|
||||
log.Debug("Attempting to append ExtendedOptions")
|
||||
if index, err := DeliveryInstructions(data).extended_options_index(); err != nil {
|
||||
extended_options_length := common.Integer([]byte{data[index]})
|
||||
now = append(current, data[index:index+extended_options_length.Int()]...)
|
||||
log.WithField("extended_options_length", extended_options_length.Int()).Debug("ExtendedOptions appended")
|
||||
} else {
|
||||
log.Debug("No ExtendedOptions to append")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func maybeAppendSize(di_flag DeliveryInstructions, di_type int, data, current []byte) (now []byte, err error) {
|
||||
log.Debug("Attempting to append Size")
|
||||
if di_type == FIRST_FRAGMENT {
|
||||
if index, err := DeliveryInstructions(data).extended_options_index(); err != nil {
|
||||
extended_options_length := common.Integer([]byte{data[index]})
|
||||
now = append(current, data[index+extended_options_length.Int():index+extended_options_length.Int()+2]...)
|
||||
log.Debug("Size appended for FIRST_FRAGMENT")
|
||||
}
|
||||
} else if di_type == FOLLOW_ON_FRAGMENT {
|
||||
if len(data) < 7 {
|
||||
log.Error("Data is too short to contain size data")
|
||||
err = errors.New("data is too short to contain size data")
|
||||
} else {
|
||||
now = append(now, data[5:7]...)
|
||||
log.Debug("Size appended for FOLLOW_ON_FRAGMENT")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func readDeliveryInstructions(data []byte) (instructions DeliveryInstructions, remainder []byte, err error) {
|
||||
log.Debug("Reading DeliveryInstructions")
|
||||
if len(data) < 1 {
|
||||
log.Error("No data provided")
|
||||
err = errors.New("no data provided")
|
||||
return
|
||||
}
|
||||
@ -775,42 +910,57 @@ func readDeliveryInstructions(data []byte) (instructions DeliveryInstructions, r
|
||||
di_data = append(di_data, data[0])
|
||||
|
||||
if di_type == FIRST_FRAGMENT {
|
||||
log.Debug("Processing FIRST_FRAGMENT")
|
||||
di_data, err = maybeAppendTunnelID(data, di_data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to append TunnelID")
|
||||
return
|
||||
}
|
||||
di_data, err = maybeAppendHash(di_flag, data, di_data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to append Hash")
|
||||
return
|
||||
}
|
||||
di_data, err = maybeAppendDelay(di_flag, data, di_data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to append Delay")
|
||||
return
|
||||
}
|
||||
di_data, err = maybeAppendMessageID(di_flag, di_type, data, di_data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to append MessageID")
|
||||
return
|
||||
}
|
||||
di_data, err = maybeAppendExtendedOptions(di_flag, data, di_data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to append ExtendedOptions")
|
||||
return
|
||||
}
|
||||
di_data, err = maybeAppendSize(di_flag, di_type, data, di_data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to append Size")
|
||||
return
|
||||
}
|
||||
} else if di_type == FOLLOW_ON_FRAGMENT {
|
||||
di_data, err = maybeAppendMessageID(di_flag, di_type, data, di_data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to append MessageID")
|
||||
return
|
||||
}
|
||||
di_data, err = maybeAppendSize(di_flag, di_type, data, di_data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to append Size")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
remainder = data[len(di_data):]
|
||||
instructions = DeliveryInstructions(di_data)
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"instructions_length": len(instructions),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully read DeliveryInstructions")
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -3,8 +3,9 @@ package tunnel
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
/*
|
||||
@ -157,12 +158,17 @@ func (decrypted_tunnel_message DecryptedTunnelMessage) Checksum() crypto.TunnelI
|
||||
// Returns the contents of a decrypted tunnel message that contain the data for the
|
||||
// DeliveryInstructions.
|
||||
func (decrypted_tunnel_message DecryptedTunnelMessage) deliveryInstructionData() []byte {
|
||||
log.Debug("Retrieving delivery instruction data from DecryptedTunnelMessage")
|
||||
data_area := decrypted_tunnel_message[4+4+16:]
|
||||
for i := 0; i < len(data_area); i++ {
|
||||
if data_area[i] == 0x00 {
|
||||
return data_area[i+1:]
|
||||
// return data_area[i+1:]
|
||||
delivery_data := data_area[i+1:]
|
||||
log.WithField("delivery_data_length", len(delivery_data)).Debug("Retrieved delivery instruction data")
|
||||
return delivery_data
|
||||
}
|
||||
}
|
||||
log.Warn("No delivery instruction data found in DecryptedTunnelMessage")
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
@ -174,7 +180,7 @@ func (decrypted_tunnel_message DecryptedTunnelMessage) DeliveryInstructionsWithF
|
||||
for {
|
||||
instructions, remainder, err := readDeliveryInstructions(data)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(DecryptedTunnelMessage) DeliveryInstructionsWithFragments",
|
||||
"err": err.Error(),
|
||||
}).Error("error reading delivery instructions")
|
||||
@ -183,7 +189,7 @@ func (decrypted_tunnel_message DecryptedTunnelMessage) DeliveryInstructionsWithF
|
||||
|
||||
fragment_size, err := instructions.FragmentSize()
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(DecryptedTunnelMessage) DeliveryInstructionsWithFragments",
|
||||
"err": err.Error(),
|
||||
}).Error("error getting delivery instructions fragment size")
|
||||
|
51
lib/util/logger/log.go
Normal file
51
lib/util/logger/log.go
Normal file
@ -0,0 +1,51 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
log *logrus.Logger
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
func InitializeGoI2PLogger() {
|
||||
once.Do(func() {
|
||||
log = logrus.New()
|
||||
// We do not want to log by default
|
||||
log.SetOutput(ioutil.Discard)
|
||||
log.SetLevel(logrus.PanicLevel)
|
||||
// Check if DEBUG_I2P is set
|
||||
if logLevel := os.Getenv("DEBUG_I2P"); logLevel != "" {
|
||||
log.SetOutput(os.Stdout)
|
||||
switch strings.ToLower(logLevel) {
|
||||
case "debug":
|
||||
log.SetLevel(logrus.DebugLevel)
|
||||
case "warn":
|
||||
log.SetLevel(logrus.WarnLevel)
|
||||
case "error":
|
||||
log.SetLevel(logrus.ErrorLevel)
|
||||
default:
|
||||
log.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
log.WithField("level", log.GetLevel()).Debug("Logging enabled.")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// GetGoI2PLogger returns the initialized logger
|
||||
func GetGoI2PLogger() *logrus.Logger {
|
||||
if log == nil {
|
||||
InitializeGoI2PLogger()
|
||||
}
|
||||
return log
|
||||
}
|
||||
|
||||
func init() {
|
||||
InitializeGoI2PLogger()
|
||||
}
|
159
main.go
159
main.go
@ -1,35 +1,162 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/config"
|
||||
"github.com/go-i2p/go-i2p/lib/router"
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/go-i2p/go-i2p/lib/util/signals"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
netDbPath := flag.String("netDb", config.DefaultNetDbConfig.Path, "Path to the netDb")
|
||||
flag.Parse()
|
||||
config.RouterConfigProperties.NetDb.Path = *netDbPath
|
||||
var (
|
||||
routerInstance *router.Router
|
||||
log = logger.GetGoI2PLogger()
|
||||
)
|
||||
|
||||
var RootCmd = &cobra.Command{
|
||||
Use: "go-i2p",
|
||||
Short: "I2P Router implementation in Go",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
runRouter()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(config.InitConfig)
|
||||
|
||||
// Global flags
|
||||
RootCmd.PersistentFlags().StringVar(&config.CfgFile, "config", "", "config file (default is $HOME/.go-i2p/config.yaml)")
|
||||
|
||||
// Router configuration flags
|
||||
RootCmd.PersistentFlags().String("base-dir", config.DefaultRouterConfig().BaseDir, "Base directory for I2P router")
|
||||
RootCmd.PersistentFlags().String("working-dir", config.DefaultRouterConfig().WorkingDir, "Working directory for I2P router")
|
||||
|
||||
// NetDb flags
|
||||
RootCmd.PersistentFlags().String("netdb.path", config.DefaultNetDbConfig.Path, "Path to the netDb")
|
||||
|
||||
// Bootstrap flags
|
||||
RootCmd.PersistentFlags().Int("bootstrap.low-peer-threshold", config.DefaultBootstrapConfig.LowPeerThreshold,
|
||||
"Minimum number of peers before reseeding")
|
||||
|
||||
// Bind flags to viper
|
||||
viper.BindPFlag("base_dir", RootCmd.PersistentFlags().Lookup("base-dir"))
|
||||
viper.BindPFlag("working_dir", RootCmd.PersistentFlags().Lookup("working-dir"))
|
||||
viper.BindPFlag("netdb.path", RootCmd.PersistentFlags().Lookup("netdb.path"))
|
||||
viper.BindPFlag("bootstrap.low_peer_threshold", RootCmd.PersistentFlags().Lookup("bootstrap.low-peer-threshold"))
|
||||
}
|
||||
|
||||
// configCmd shows current configuration
|
||||
var configCmd = &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "Show current configuration",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Printf("Configuration file: %s\n", viper.ConfigFileUsed())
|
||||
fmt.Printf("\nRouter Configuration:")
|
||||
fmt.Printf(" Base Directory: %s", config.RouterConfigProperties.BaseDir)
|
||||
fmt.Printf(" Working Directory: %s", config.RouterConfigProperties.WorkingDir)
|
||||
|
||||
fmt.Printf("\nNetDb Configuration:")
|
||||
fmt.Printf(" Path: %s", config.RouterConfigProperties.NetDb.Path)
|
||||
|
||||
fmt.Printf("\nBootstrap Configuration:")
|
||||
fmt.Printf(" Low Peer Threshold: %d", config.RouterConfigProperties.Bootstrap.LowPeerThreshold)
|
||||
fmt.Printf(" Reseed Servers:")
|
||||
for _, server := range config.RouterConfigProperties.Bootstrap.ReseedServers {
|
||||
fmt.Printf(" - URL: %s", server.Url)
|
||||
fmt.Printf(" SU3 Fingerprint: %s", server.SU3Fingerprint)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func debugPrintConfig() {
|
||||
currentConfig := struct {
|
||||
BaseDir string `yaml:"base_dir"`
|
||||
WorkingDir string `yaml:"working_dir"`
|
||||
NetDB config.NetDbConfig `yaml:"netdb"`
|
||||
Bootstrap config.BootstrapConfig `yaml:"bootstrap"`
|
||||
}{
|
||||
BaseDir: config.RouterConfigProperties.BaseDir,
|
||||
WorkingDir: config.RouterConfigProperties.WorkingDir,
|
||||
NetDB: *config.RouterConfigProperties.NetDb,
|
||||
Bootstrap: *config.RouterConfigProperties.Bootstrap,
|
||||
}
|
||||
|
||||
yamlData, err := yaml.Marshal(currentConfig)
|
||||
if err != nil {
|
||||
log.Errorf("Error marshaling config for debug: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("Current configuration:\n%s", string(yamlData))
|
||||
}
|
||||
|
||||
func runRouter() {
|
||||
go signals.Handle()
|
||||
log.Info("parsing i2p router configuration")
|
||||
log.Info("using netDb in:", config.RouterConfigProperties.NetDb.Path)
|
||||
log.Info("starting up i2p router")
|
||||
r, err := router.CreateRouter()
|
||||
|
||||
log.Debug("parsing i2p router configuration")
|
||||
log.Debug("using netDb in:", config.RouterConfigProperties.NetDb.Path)
|
||||
log.Debug("starting up i2p router")
|
||||
|
||||
var err error
|
||||
routerInstance, err = router.CreateRouter(config.RouterConfigProperties)
|
||||
if err == nil {
|
||||
signals.RegisterReloadHandler(func() {
|
||||
// TODO: reload config
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
log.Errorf("failed to reload config: %s", err)
|
||||
return
|
||||
}
|
||||
config.UpdateRouterConfig()
|
||||
})
|
||||
|
||||
signals.RegisterInterruptHandler(func() {
|
||||
// TODO: graceful shutdown
|
||||
r.Stop()
|
||||
if routerInstance != nil {
|
||||
routerInstance.Stop()
|
||||
}
|
||||
})
|
||||
r.Start()
|
||||
r.Wait()
|
||||
r.Close()
|
||||
|
||||
routerInstance.Start()
|
||||
routerInstance.Wait()
|
||||
routerInstance.Close()
|
||||
} else {
|
||||
log.Errorf("failed to create i2p router: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
RootCmd.AddCommand(configCmd)
|
||||
if err := RootCmd.Execute(); err != nil {
|
||||
log.Error(err)
|
||||
debugPrintConfig()
|
||||
os.Exit(1)
|
||||
}
|
||||
/*
|
||||
netDbPath := flag.String("netDb", config.DefaultNetDbConfig.Path, "Path to the netDb")
|
||||
flag.Parse()
|
||||
config.RouterConfigProperties.NetDb.Path = *netDbPath
|
||||
go signals.Handle()
|
||||
log.Debug("parsing i2p router configuration")
|
||||
log.Debug("using netDb in:", config.RouterConfigProperties.NetDb.Path)
|
||||
log.Debug("starting up i2p router")
|
||||
r, err := router.CreateRouter()
|
||||
if err == nil {
|
||||
signals.RegisterReloadHandler(func() {
|
||||
// TODO: reload config
|
||||
})
|
||||
signals.RegisterInterruptHandler(func() {
|
||||
// TODO: graceful shutdown
|
||||
r.Stop()
|
||||
})
|
||||
r.Start()
|
||||
r.Wait()
|
||||
r.Close()
|
||||
} else {
|
||||
log.Errorf("failed to create i2p router: %s", err)
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
Reference in New Issue
Block a user