117 Commits

Author SHA1 Message Date
eyedeekay
3c54c74ac3 re-add docs 2024-10-30 18:56:20 -04:00
eyedeekay
80e539930e Mapping: fix off-by-one. Format: gofumpt 2024-10-28 18:11:54 -04:00
Haris Khan
e58d326d89 Move obfuscation functions to lib/transport/ntcp 2024-10-25 21:29:02 -04:00
Haris Khan
e6f84c16f6 added experimental functions which factor in packet length
-encryptPacketDeux
-decryptPacketDeux

Added test -> TestEncryptDecryptPacketObfsOfflineWithFunc()

added new functions in aes.go
-EncryptNoPadding
-DecryptNoPadding
2024-10-24 22:57:36 -04:00
Haris Khan
971a18de8d added Compatible warning message 2024-10-24 19:23:36 -04:00
Haris Khan
833836ae67 added TestEncryptDecryptPacketObfsOffline 2024-10-24 18:58:07 -04:00
Haris Khan
3f191db37a implement TODO for Compatible in NoiseTransport 2024-10-24 18:03:20 -04:00
idk
6865bae386 Merge pull request #17 from hkh4n/dirs
create ~/go-i2p and ~/go-i2p/config properly
2024-10-24 20:12:06 +00:00
Haris Khan
f0d9f89ed9 Mkdir -> MkdirAll 2024-10-24 14:26:51 -04:00
idk
c149eef1de Merge pull request #15 from hkh4n/makefile
Makefiles for tests + hotfix for logging naming convention
2024-10-23 17:34:06 +00:00
Haris Khan
748dc8a66f tweaks 2024-10-23 00:11:46 -04:00
Haris Khan
677aac500e fix logger naming collision with other libs 2024-10-23 00:06:06 -04:00
Haris Khan
4e06d3d5ed makefiles 2024-10-22 22:31:19 -04:00
Haris Khan
5eaa9cf588 log name collision fix 2024-10-22 22:10:14 -04:00
Haris Khan
4dbf537e94 log name collision fix 2024-10-22 22:07:39 -04:00
Haris Khan
882c018c0c log name collision fix 2024-10-22 22:06:06 -04:00
Haris Khan
5432502852 typo correction 2024-10-22 21:43:49 -04:00
idk
0ea5743365 Merge pull request #14 from hkh4n/noise-experimental
gofumpt adjustment
2024-10-22 21:53:24 +00:00
Haris Khan
a9dc482bda gofumpt 2024-10-22 17:37:17 -04:00
idk
c31d20fec0 Merge pull request #13 from hkh4n/logging
Logging
2024-10-22 18:55:15 +00:00
Haris Khan
647546a374 typo fix 2024-10-22 14:51:17 -04:00
Haris Khan
0256908395 CRITICAL FIX, bytesRead -> n.
n wasn't being used before
2024-10-19 17:27:39 -04:00
Haris Khan
3c5aa206d1 expanded logging in message.go 2024-10-19 12:32:49 -04:00
Haris Khan
a4517cafd7 expanded logging in delivery.go 2024-10-19 12:25:31 -04:00
Haris Khan
f4f39ca53c expanded logging in multi.go 2024-10-19 11:18:20 -04:00
Haris Khan
220159476a expanded logging in write_session.go 2024-10-19 11:09:37 -04:00
Haris Khan
792cd49208 expanded logging in transport.go 2024-10-19 11:03:55 -04:00
Haris Khan
68051630c0 expanded logging in session.go 2024-10-19 10:55:30 -04:00
Haris Khan
a3340eb40a expanded logging in read_session.go + changed structure in readPacketLocked() 2024-10-19 10:50:13 -04:00
Haris Khan
465a7787a9 expanded logging in outgoing_handshake.go 2024-10-19 10:44:08 -04:00
Haris Khan
af3bc44dba expanded logging in incoming_handshake.go 2024-10-19 10:39:23 -04:00
Haris Khan
f850f482cf expanded logging in handshake.go 2024-10-19 10:30:11 -04:00
Haris Khan
3f23376d22 expanded logging in su3.go 2024-10-19 10:19:55 -04:00
Haris Khan
aa98589f1c expanded logging in router.go 2024-10-19 09:46:23 -04:00
Haris Khan
c31e990995 expanded logging in std.go 2024-10-18 23:06:44 -04:00
Haris Khan
8e97eb5f77 expanded logging in reseed.go 2024-10-18 22:54:08 -04:00
Haris Khan
be35267079 expanded logging in header.go 2024-10-18 22:47:28 -04:00
Haris Khan
013d35b447 expanded logging in build_request_record.go 2024-10-18 22:41:40 -04:00
Haris Khan
e8c9dc17a3 expanded logging in tunnel.go 2024-10-18 21:58:50 -04:00
Haris Khan
a1d574446b expanded logging in elg.go 2024-10-18 21:54:27 -04:00
Haris Khan
8680acc595 expanded logging in ed25519.go 2024-10-18 21:42:07 -04:00
Haris Khan
84e3c5accc expanded logging in ecdsa.go 2024-10-18 17:01:42 -04:00
Haris Khan
e772fb5ceb expanded logging in dsa.go 2024-10-18 16:56:25 -04:00
Haris Khan
a533cd7ce4 expanded logging in curve25519.go 2024-10-18 16:39:28 -04:00
Haris Khan
df37d49444 expanded logging to aes.go 2024-10-18 15:10:16 -04:00
Haris Khan
4b2600a065 expanded logging to signature.go
-changed sessionTag -> sig
2024-10-18 14:55:30 -04:00
Haris Khan
1c4f937002 expanded logging to session_tag.go 2024-10-18 14:51:53 -04:00
Haris Khan
5c2b408f65 expanded logging to session_key.go 2024-10-18 14:43:59 -04:00
Haris Khan
beb533a09b expanded logging to router_info.go 2024-10-18 14:40:52 -04:00
Haris Khan
f022522ad5 expanded logging to router_identity.go 2024-10-18 14:27:41 -04:00
Haris Khan
2191c40ac6 expanded logging to router_address.go + gofumpt adjustment 2024-10-18 13:22:36 -04:00
Haris Khan
3bca467f28 updated README.md to reflect new logging paradigm. 2024-10-18 12:59:49 -04:00
Haris Khan
a2fd65ee32 expanded logging in lease_set.go 2024-10-18 12:55:35 -04:00
Haris Khan
b894e8fb17 expanded logging in keys_and_cert.go 2024-10-18 12:41:48 -04:00
Haris Khan
93a71c7398 expanded logging in key_certificate.go 2024-10-18 12:27:42 -04:00
Haris Khan
b6544ad194 expanded logging in destination.go 2024-10-18 12:16:36 -04:00
Haris Khan
a72b61a886 expanded logging in string.go 2024-10-18 12:08:27 -04:00
Haris Khan
dda4f90b6f expanded logging in mapping_values.go 2024-10-18 12:00:58 -04:00
Haris Khan
1d1d8126c2 adjusted logging in main.go 2024-10-18 11:53:01 -04:00
Haris Khan
73db39ae50 expanded logging in mapping.go 2024-10-18 11:52:39 -04:00
Haris Khan
53e902f491 expanded logging to date.go 2024-10-18 11:49:10 -04:00
Haris Khan
2f2cd2249c expanded logging to certificate.go 2024-10-18 11:48:56 -04:00
Haris Khan
4496c11394 added lib/util/logger/log.go 2024-10-17 22:03:46 -04:00
idk
69449a20b5 Merge pull request #12 from hkh4n/crypto2
AES
2024-10-17 23:48:13 +00:00
Haris Khan
a7689e801a minor typo 2024-10-06 12:13:04 -04:00
Haris Khan
278bdee277 Various changes
-Aes -> AES
-doc.md
2024-10-06 10:48:22 -04:00
Haris Khan
684e89c957 minor typo 2024-10-05 10:15:31 -04:00
Haris Khan
50fa9fc374 gofumpt adjustment 2024-10-05 09:43:58 -04:00
Haris Khan
491b25022e AES
-Revamped encrypt and decrypt to fit with interfaces
-Adjusted test cases for TestPKCS7UnpadInvalidInput()
2024-10-05 09:00:33 -04:00
Haris Khan
677a6b354b AES test 2024-10-04 22:37:57 -04:00
Haris Khan
9469fd83aa AES 2024-10-04 22:36:32 -04:00
idk
8173ae49e6 Merge pull request #10 from hkh4n/makefile
Added gofumpt check
2024-10-04 03:26:01 +00:00
Haris Khan
2f109d5b4d Added gofumpt check 2024-10-03 23:24:12 -04:00
eyedeekay
d7378d7b08 more merge conflicts 2024-10-03 22:46:39 -04:00
eyedeekay
3a51a1229e more merge conflicts 2024-10-03 22:45:33 -04:00
eyedeekay
2b18b2941d resolve merge conflicts in lib/transport/noise 2024-10-03 22:42:00 -04:00
eyedeekay
1eb29ec4ab formatting issues only 2024-10-03 22:36:23 -04:00
eyedeekay
d900d7faf8 add doc.md files from master 2024-10-03 22:10:55 -04:00
eyedeekay
03c9d60ab9 update other non-transport parts of lib 2024-10-03 22:09:16 -04:00
eyedeekay
de2caf499e use makefile from Master 2024-10-03 21:58:16 -04:00
eyedeekay
284dd7287e use makefile from Master 2024-10-03 21:56:58 -04:00
eyedeekay
9f4154ff45 gofmt 2024-10-03 21:55:35 -04:00
eyedeekay
08a0d92742 gofmt 2024-10-03 21:52:49 -04:00
eyedeekay
524526d946 Bring in crypto stubs from master 2024-10-03 21:41:31 -04:00
eyedeekay
09c7d32797 update the common library to the master branch 2024-10-03 21:31:54 -04:00
Haris Khan
16961abc96 !WIP!
-added error handling in TestTransport()
-fixed typo to ComposeReceiverHandshakeMessage
-experimental implementation of encryptPacket
-added encrdecr_packet_test.go
2024-10-03 19:45:17 -04:00
eyedeekay
0c7a3f0f22 force static builds for slightly easier debugging 2024-09-09 20:13:20 -04:00
eyedeekay
3d535f67a1 Work on curve25519 stuff so I can generate my own routerInfos instead of just sending crap to other people 2024-09-09 20:10:38 -04:00
eyedeekay
bba9350506 WOO some of the important fields are actually populated with correct values 2024-08-28 20:47:54 -04:00
eyedeekay
cbc0de4e7e Start working on de-obfuscating ephemeral keys from remote peers 2024-08-28 18:32:42 -04:00
eyedeekay
310ef07d3c generate godoc locally so I can go over it offline 2024-08-26 16:21:54 -04:00
eyedeekay
14fc6fc3a8 Work on noise tools, comment details of handshake stuff 2024-08-25 23:22:21 -04:00
eyedeekay
a3ce9d36c6 If string data is shorter than specified by length create a new string based on the content after the first byte 2024-07-08 10:46:16 -04:00
eyedeekay
58a43cdfaf Fix string length checks, sortof 2024-07-05 23:12:03 -04:00
eyedeekay
15a5ca5daf Try and make noise work and also fix some tests 2024-07-05 18:12:58 -04:00
eyedeekay
08a41686b6 Work on noise wrapper. It is now good enough to fail to connect to a remote I2P router in a way which is discernible on that remote router. 2024-07-03 01:19:31 -04:00
eyedeekay
8318fd8f57 Work on noise wrapper. It is now good enough to fail to connect to a remote I2P router in a way which is discernible on that remote router. 2024-07-03 01:17:36 -04:00
eyedeekay
9c0552e236 Make some netDb loading stuff work so I have RI's to talk to 2024-07-02 16:54:30 -04:00
eyedeekay
20b018a708 Make some netDb loading stuff work so I have RI's to talk to 2024-07-02 16:53:57 -04:00
eyedeekay
6c62faa49b finish stubbing out noise transport stuff 2024-07-01 21:37:05 -04:00
eyedeekay
a7e31b7833 implement more noise stuff 2024-07-01 21:34:09 -04:00
eyedeekay
c09161c824 check in beginnings of new cleaned-up noise prototype 2024-07-01 18:50:13 -04:00
eyedeekay
aca62174e6 Load RI's into netDb struct for later referencing 2024-06-30 23:14:48 -04:00
eyedeekay
bd27f00959 add my unzip fork which fixes the permissions bug 2024-06-29 00:36:11 -04:00
eyedeekay
05c4d3d973 add my unzip fork which fixes the permissions bug 2024-06-29 00:25:23 -04:00
eyedeekay
40d0ea5ff5 Start making it so I can configure things, so I can configure it to read the netDb I already have and attempt to make a connection. Implement a reseed puller, or at least most of one. 2024-06-29 00:23:55 -04:00
eyedeekay
58e8f78c56 Start making it so I can configure things, so I can configure it to read the netDb I already have and attempt to make a connection. Implement a reseed puller, or at least most of one. 2024-06-29 00:23:42 -04:00
idk
65febb5dcf Work on organizing this Noise over TCP Socket stuff 2022-12-15 23:52:05 +00:00
idk
116e22f8da Try to figure out how to implement the pieces I'm still missing from the Noise handshake, but I think that I probably need to redo it again anyway 2022-12-12 17:44:43 +00:00
idk
0419665d7b use separate incoming and outgoing queues 2022-11-14 00:10:58 -05:00
idk
dab108c270 Client=>Outgoing 2022-11-13 23:46:57 -05:00
idk
0fcded4c51 check in more noise handshake missing pieces 2022-11-13 22:24:31 -05:00
idk
7d16b0b257 update my notes 2022-10-17 02:16:44 -04:00
idk
a689f26d73 fix merge conflicts 2022-10-17 02:07:11 -04:00
idk
fdc34b382e Fix some tests so it compiles again 2022-10-16 17:19:38 -04:00
idk
a4ed06e530 update my notes 2022-09-26 12:18:33 -04:00
idk
6b5ea57cbd Move my noise transport tests to a branch so I don't mess up the other branch 2022-09-19 14:35:49 -04:00
148 changed files with 8605 additions and 770 deletions

2
.gitignore vendored
View File

@@ -7,3 +7,5 @@
go-i2p
*.exe
.idea/
router.info
log

View File

@@ -2,6 +2,7 @@ RELEASE_TAG=0.0.1
RELEASE_VERSION=${RELEASE_TAG}
RELEASE_DESCRIPTION=`cat PASTA.md`
REPO := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
CGO_ENABLED=0
ifdef GOROOT
GO = $(GOROOT)/bin/go
@@ -15,19 +16,23 @@ else
EXE := $(REPO)/go-i2p
endif
#check for gofumpt
check_gofumpt:
@which gofumpt > /dev/null 2>&1 || (echo "gofumpt is required but not installed. Please install it from https://github.com/mvdan/gofumpt."; exit 1)
build: clean $(EXE)
$(EXE):
$(GO) build -v -o $(EXE)
$(GO) build --tags netgo,osusergo -v -o $(EXE)
test: fmt
$(GO) test -vv -failfast ./lib/common/...
test: check_gofumpt fmt
$(GO) test -v -failfast ./lib/common/...
clean:
$(GO) clean -v
fmt:
find . -name '*.go' -exec gofmt -w -s {} \;
find . -name '*.go' -exec gofumpt -w {} \;
info:
echo "GOROOT: ${GOROOT}"
@@ -36,3 +41,36 @@ info:
release:
github-release release -u go-i2p -r go-i2p -n "${RELEASE_VERSION}" -t "${RELEASE_TAG}" -d "${RELEASE_DESCRIPTION}" -p
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 ./{}" \;
# 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

View File

@@ -41,7 +41,7 @@ please keep up with these changes, as they will not be backward compatible and r
- [ ] Elligator2
- [ ] HKDF
- [ ] HMAC
- [ ] Noise subsystem
- [/] Noise subsystem
- End-to-End Crypto
- [ ] Garlic messages
- [ ] ElGamal/AES+SessionTag
@@ -50,7 +50,7 @@ please keep up with these changes, as they will not be backward compatible and r
- [ ] Message parsing
- [ ] Message handling
- NetDB
- [ ] Local storage
- [/] Local storage
- [/] Persistence to disk
- [X] Reseeding
- [ ] Lookups
@@ -79,7 +79,7 @@ please keep up with these changes, as they will not be backward compatible and r
- [ ] Tunnel Message Crypto
- [ ] Tunnel Message Fragmentation/Reassembly
- Common Data Structures
- [/] Keys and Cert
- [X] Keys and Cert
- [X] Key Certificates
- [X] Certificate
- [X] Lease
@@ -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
View 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
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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

View 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
View 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
View 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

View File

@@ -0,0 +1,2 @@
test-mapping-values-order:
go test -v ./lib/common/data -run TestMappingOrderSortsValuesThenKeys

11
doc/tests/noise.mk Normal file
View File

@@ -0,0 +1,11 @@
test-noise-transport-all: test-noise-packet-encryption test-noise-transport-connection
test-noise-packet-encryption:
go test -v ./lib/transport/noise -run TestEncryptDecryptPacketOffline
test-noise-transport-connection:
go test -v ./lib/transport/noise -run TestTransport
.PHONY: test-noise-transport-all \
test-noise-packet-encryption \
test-noise-transport-connection

View 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
View 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
View 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
View 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
View 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

16
go.mod
View File

@@ -1,11 +1,21 @@
module github.com/go-i2p/go-i2p
go 1.16
go 1.23.1
require (
github.com/emirpasic/gods v1.18.1
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e
github.com/flynn/noise v1.1.0
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.7.0
golang.org/x/crypto v0.23.0
github.com/stretchr/testify v1.9.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.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.25.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

56
go.sum
View File

@@ -1,8 +1,12 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
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/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/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
@@ -15,57 +19,25 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
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.53.0 h1:+1as1ogzuCzx15/468M4mEC5juogI5a0Fzbsyh1CuYY=
go.step.sm/crypto v0.53.0/go.mod h1:AqLU78RqNUHepLzyOWZuNN/2++Lu7dZENdO9UzWOGSk=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
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/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.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/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
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=

23
lib/bootstrap/doc.md Normal file
View File

@@ -0,0 +1,23 @@
# bootstrap
--
import "github.com/go-i2p/go-i2p/lib/bootstrap"
provides generic interfaces for initial bootstrap into network and network
### reseeding
## Usage
#### type Bootstrap
```go
type Bootstrap interface {
// get more peers for bootstrap
// try obtaining at most n router infos
// if n is 0 then try obtaining as many router infos as possible
// returns nil and error if we cannot fetch ANY router infos
// returns a channel that yields 1 slice of router infos containing n or fewer router infos, caller must close channel after use
GetPeers(n int) (chan []router_info.RouterInfo, error)
}
```
interface defining a way to bootstrap into the i2p network

33
lib/common/base32/doc.md Normal file
View File

@@ -0,0 +1,33 @@
# base32
--
import "github.com/go-i2p/go-i2p/lib/common/base32"
Package base32 implmenets utilities for encoding and decoding text using I2P's
### alphabet
## Usage
```go
const I2PEncodeAlphabet = "abcdefghijklmnopqrstuvwxyz234567"
```
I2PEncodeAlphabet is the base32 encoding used throughout I2P. RFC 3548 using
lowercase characters.
```go
var I2PEncoding *b32.Encoding = b32.NewEncoding(I2PEncodeAlphabet)
```
I2PEncoding is the standard base32 encoding used through I2P.
#### func DecodeString
```go
func DecodeString(data string) ([]byte, error)
```
DecodeString decodes base64 string to []byte I2PEncoding
#### func EncodeToString
```go
func EncodeToString(data []byte) string
```
EncodeToString encodes []byte to a base32 string using I2PEncoding

33
lib/common/base64/doc.md Normal file
View File

@@ -0,0 +1,33 @@
# base64
--
import "github.com/go-i2p/go-i2p/lib/common/base64"
Package base64 implmenets utilities for encoding and decoding text using I2P's
### alphabet
## Usage
```go
const I2PEncodeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~"
```
I2PEncodeAlphabet is the base64 encoding used throughout I2P. RFC 4648 with "/""
replaced with "~", and "+" replaced with "-".
```go
var I2PEncoding *b64.Encoding = b64.NewEncoding(I2PEncodeAlphabet)
```
I2PEncoding is the standard base64 encoding used through I2P.
#### func DecodeString
```go
func DecodeString(str string) ([]byte, error)
```
DecodeString decodes base64 string to []byte I2PEncoding
#### func EncodeToString
```go
func EncodeToString(data []byte) string
```
I2PEncoding is the standard base64 encoding used through I2P.

View File

@@ -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,12 +75,23 @@ 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 {
return c.payload[c.len.Int():]
if len(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
}
// Bytes returns the entire certificate in []byte form, trims payload to specified length.
@@ -83,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
}
@@ -94,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
}
@@ -108,31 +133,35 @@ 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
}
// NewCertificate creates a new Certficiate from []byte
// returns err if the certificate is too short or if the payload doesn't match specified length.
func NewCertificate(data []byte) (certificate *Certificate, err error) {
certificate = &Certificate{}
func NewCertificate(data []byte) (certificate Certificate, err error) {
certificate = Certificate{}
switch len(data) {
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()),
}).Error("invalid certificate, empty")
err = fmt.Errorf("error parsing certificate: certificate is empty")
return
case 1 , 2:
certificate.kind = Integer(data[0:len(data)-1])
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()),
@@ -146,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,
@@ -157,17 +186,25 @@ 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
}
}
// ReadCertificate creates a Certificate from []byte and returns any ExcessBytes at the end of the input.
// returns err if the certificate could not be read.
func ReadCertificate(data []byte) (certificate *Certificate, remainder []byte, err error) {
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
}

View File

@@ -32,12 +32,12 @@ func TestCertificateLengthErrWhenTooShort(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x01}
certificate, err := NewCertificate(bytes)
certificate, _, err := ReadCertificate(bytes)
cert_len := certificate.Length()
assert.Equal(cert_len, 0, "certificate.Length() did not return zero length for missing length data")
if assert.NotNil(err) {
assert.Equal("error parsing certificate length: certificate is too short", err.Error(), "correct error message should be returned")
assert.Equal("error parsing certificate: certificate is too short", err.Error(), "correct error message should be returned")
}
}
@@ -71,13 +71,10 @@ func TestCertificateDataWhenTooLong(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff, 0xaa, 0xaa}
certificate, err := NewCertificate(bytes)
certificate, _, _ := ReadCertificate(bytes)
cert_data := certificate.Data()
if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is longer than specified by length", err.Error(), "correct error message should be returned")
}
cert_len := certificate.Length() //len(cert_data)
cert_len := certificate.Length() // len(cert_data)
assert.Equal(cert_len, 2, "certificate.Length() did not return indicated length when data was too long")
if cert_data[0] != 0xff || cert_data[1] != 0xff {
t.Fatal("certificate.Data() returned incorrect data when data was too long")
@@ -144,6 +141,6 @@ func TestReadCertificateWithInvalidLength(t *testing.T) {
assert.Equal(cert.length(), 2, "ReadCertificate() should populate the certificate with the provided data even when invalid")
assert.Equal(len(remainder), 0, "ReadCertificate() returned non-zero length remainder on invalid certificate")
if assert.NotNil(err) {
assert.Equal("error parsing certificate length: certificate is too short", err.Error(), "correct error message should be returned")
assert.Equal("error parsing certificate: certificate is too short", err.Error(), "correct error message should be returned")
}
}

View File

@@ -0,0 +1,98 @@
# certificate
--
import "github.com/go-i2p/go-i2p/lib/common/certificate"
## Usage
```go
const (
CERT_NULL = iota
CERT_HASHCASH
CERT_HIDDEN
CERT_SIGNED
CERT_MULTIPLE
CERT_KEY
)
```
Certificate Types
```go
const CERT_MIN_SIZE = 3
```
CERT_MIN_SIZE is the minimum size of a valid Certificate in []byte 1 byte for
type 2 bytes for payload length
#### type Certificate
```go
type Certificate struct {
}
```
Certificate is the representation of an I2P Certificate.
https://geti2p.net/spec/common-structures#certificate
#### func NewCertificate
```go
func NewCertificate(data []byte) (certificate Certificate, err error)
```
NewCertificate creates a new Certficiate from []byte returns err if the
certificate is too short or if the payload doesn't match specified length.
#### func ReadCertificate
```go
func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, err error)
```
ReadCertificate creates a Certificate from []byte and returns any ExcessBytes at
the end of the input. returns err if the certificate could not be read.
#### func (*Certificate) Bytes
```go
func (c *Certificate) Bytes() []byte
```
Bytes returns the entire certificate in []byte form, trims payload to specified
length.
#### func (*Certificate) Data
```go
func (c *Certificate) Data() (data []byte)
```
Data returns the payload of a Certificate, payload is trimmed to the specified
length.
#### func (*Certificate) ExcessBytes
```go
func (c *Certificate) ExcessBytes() []byte
```
ExcessBytes returns the excess bytes in a certificate found after the specified
payload length.
#### func (*Certificate) Length
```go
func (c *Certificate) Length() (length int)
```
Length returns the payload length of a Certificate.
#### func (*Certificate) RawBytes
```go
func (c *Certificate) RawBytes() []byte
```
RawBytes returns the entire certificate in []byte form, includes excess payload
data.
#### func (*Certificate) Type
```go
func (c *Certificate) Type() (cert_type int)
```
Type returns the Certificate type specified in the first byte of the
Certificate,

View File

@@ -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
}

View File

@@ -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}

297
lib/common/data/doc.md Normal file
View File

@@ -0,0 +1,297 @@
# data
--
import "github.com/go-i2p/go-i2p/lib/common/data"
Package data implements common data structures used in higher level structures.
## Usage
```go
const DATE_SIZE = 8
```
DATE_SIZE is the length in bytes of an I2P Date.
```go
const MAX_INTEGER_SIZE = 8
```
MAX_INTEGER_SIZE is the maximum length of an I2P integer in bytes.
```go
const STRING_MAX_SIZE = 255
```
STRING_MAX_SIZE is the maximum number of bytes that can be stored in an I2P
string
#### func PrintErrors
```go
func PrintErrors(errs []error)
```
PrintErrors prints a formatted list of errors to the console.
#### func WrapErrors
```go
func WrapErrors(errs []error) error
```
WrapErrors compiles a slice of errors and returns them wrapped together as a
single error.
#### type Date
```go
type Date [8]byte
```
Date is the represenation of an I2P Date.
https://geti2p.net/spec/common-structures#date
#### func NewDate
```go
func NewDate(data []byte) (date *Date, remainder []byte, err error)
```
NewDate creates a new Date from []byte using ReadDate. Returns a pointer to Date
unlike ReadDate.
#### func ReadDate
```go
func ReadDate(data []byte) (date Date, remainder []byte, err error)
```
ReadDate creates a Date from []byte using the first DATE_SIZE bytes. Any data
after DATE_SIZE is returned as a remainder.
#### func (Date) Bytes
```go
func (i Date) Bytes() []byte
```
Bytes returns the raw []byte content of a Date.
#### func (Date) Int
```go
func (i Date) Int() int
```
Int returns the Date as a Go integer.
#### func (Date) Time
```go
func (date Date) Time() (date_time time.Time)
```
Time takes the value stored in date as an 8 byte big-endian integer representing
the number of milliseconds since the beginning of unix time and converts it to a
Go time.Time struct.
#### type Hash
```go
type Hash [32]byte
```
Hash is the represenation of an I2P Hash.
https://geti2p.net/spec/common-structures#hash
#### func HashData
```go
func HashData(data []byte) (h Hash)
```
HashData returns the SHA256 sum of a []byte input as Hash.
#### func HashReader
```go
func HashReader(r io.Reader) (h Hash, err error)
```
HashReader returns the SHA256 sum from all data read from an io.Reader. return
error if one occurs while reading from reader
#### func (Hash) Bytes
```go
func (h Hash) Bytes() [32]byte
```
#### type I2PString
```go
type I2PString []byte
```
I2PString is the represenation of an I2P String.
https://geti2p.net/spec/common-structures#string
#### func ReadI2PString
```go
func ReadI2PString(data []byte) (str I2PString, remainder []byte, err error)
```
ReadI2PString returns I2PString from a []byte. The remaining bytes after the
specified length are also returned. Returns a list of errors that occurred
during parsing.
#### func ToI2PString
```go
func ToI2PString(data string) (str I2PString, err error)
```
ToI2PString converts a Go string to an I2PString. Returns error if the string
exceeds STRING_MAX_SIZE.
#### func (I2PString) Data
```go
func (str I2PString) Data() (data string, err error)
```
Data returns the I2PString content as a string trimmed to the specified length
and not including the length byte. Returns error encountered by Length.
#### func (I2PString) Length
```go
func (str I2PString) Length() (length int, err error)
```
Length returns the length specified in the first byte. Returns error if the
specified does not match the actual length or the string is otherwise invalid.
#### type Integer
```go
type Integer []byte
```
Integer is the represenation of an I2P Integer.
https://geti2p.net/spec/common-structures#integer
#### func NewInteger
```go
func NewInteger(bytes []byte, size int) (integer *Integer, remainder []byte, err error)
```
NewInteger creates a new Integer from []byte using ReadInteger. Limits the
length of the created Integer to MAX_INTEGER_SIZE. Returns a pointer to Integer
unlike ReadInteger.
#### func NewIntegerFromInt
```go
func NewIntegerFromInt(value int, size int) (integer *Integer, err error)
```
NewIntegerFromInt creates a new Integer from a Go integer of a specified []byte
length.
#### func ReadInteger
```go
func ReadInteger(bytes []byte, size int) (Integer, []byte)
```
ReadInteger returns an Integer from a []byte of specified length. The remaining
bytes after the specified length are also returned.
#### func (Integer) Bytes
```go
func (i Integer) Bytes() []byte
```
Bytes returns the raw []byte content of an Integer.
#### func (Integer) Int
```go
func (i Integer) Int() int
```
Int returns the Date as a Go integer
#### type Mapping
```go
type Mapping struct {
}
```
Mapping is the represenation of an I2P Mapping.
https://geti2p.net/spec/common-structures#mapping
#### func GoMapToMapping
```go
func GoMapToMapping(gomap map[string]string) (mapping *Mapping, err error)
```
GoMapToMapping converts a Go map of unformatted strings to *Mapping.
#### func NewMapping
```go
func NewMapping(bytes []byte) (values *Mapping, remainder []byte, err []error)
```
NewMapping creates a new *Mapping from []byte using ReadMapping. Returns a
pointer to Mapping unlike ReadMapping.
#### func ReadMapping
```go
func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error)
```
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 ValuesToMapping
```go
func ValuesToMapping(values MappingValues) *Mapping
```
ValuesToMapping creates a *Mapping using MappingValues. The values are sorted in
the order defined in mappingOrder.
#### func (*Mapping) Data
```go
func (mapping *Mapping) Data() []byte
```
Data returns a Mapping in its []byte form.
#### func (*Mapping) HasDuplicateKeys
```go
func (mapping *Mapping) HasDuplicateKeys() bool
```
HasDuplicateKeys returns true if two keys in a mapping are identical.
#### func (Mapping) Values
```go
func (mapping Mapping) Values() MappingValues
```
Values returns the values contained in a Mapping as MappingValues.
#### type MappingValues
```go
type MappingValues [][2]I2PString
```
MappingValues represents the parsed key value pairs inside of an I2P Mapping.
#### func ReadMappingValues
```go
func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingValues, remainder_bytes []byte, errs []error)
```
ReadMappingValues returns *MappingValues from a []byte. The remaining bytes
after the specified length are also returned. Returns a list of errors that
occurred during parsing.
#### func (MappingValues) Get
```go
func (m MappingValues) Get(key I2PString) I2PString
```

View File

@@ -23,8 +23,13 @@ Contents
// https://geti2p.net/spec/common-structures#hash
type Hash [32]byte
func (h Hash) Bytes() [32]byte {
return h
}
// HashData returns the SHA256 sum of a []byte input as Hash.
func HashData(data []byte) (h Hash) {
// log.Println("Hashing Data:", data)
h = sha256.Sum256(data)
return
}

View File

@@ -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
}

View File

@@ -27,7 +27,6 @@ func TestValuesExclusesPairWithBadData(t *testing.T) {
assert.Equal(key, "a", "Values() returned by data with invalid key contains incorrect present key")
assert.Equal(val, "b", "Values() returned by data with invalid key contains incorrect present key")
}
}
func TestValuesWarnsMissingData(t *testing.T) {

View File

@@ -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,
@@ -58,11 +75,16 @@ func mappingOrder(values MappingValues) {
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingValues, remainder_bytes []byte, errs []error) {
//mapping := remainder
//var remainder = mapping
//var err error
// 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,
@@ -92,7 +114,7 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
encounteredKeysMap := map[string]bool{}
// pop off length bytes before parsing kv pairs
//remainder = remainder[2:]
// remainder = remainder[2:]
for {
// Read a key, breaking on fatal errors
@@ -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")
@@ -116,19 +138,19 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
if err != nil {
if stopValueRead(err) {
errs = append(errs, err)
//return
// return
}
}
// overwriting remainder with more as another var to prevent memory weirdness in loops
remainder = more
//log.Printf("(MAPPING VALUES DEBUG) Remainder: %s\n", remainder)
// log.Printf("(MAPPING VALUES DEBUG) Remainder: %s\n", remainder)
// Check if key has already been encountered in this mapping
keyBytes, _ := key_str.Data()
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),
@@ -160,15 +182,15 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
if err != nil {
if stopValueRead(err) {
errs = append(errs, err)
//return
// return
}
}
// overwriting remainder with more as another var to prevent memory weirdness in loops
remainder = more
//log.Printf("(MAPPING VALUES DEBUG) Remainder: %s\n", remainder)
//log.Printf("(MAPPING VALUES DEBUG) String: value: %s", val_str)
// 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,6 +211,12 @@ func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingVal
encounteredKeysMap[keyAsString] = true
}
values = &map_values
return
log.WithFields(logrus.Fields{
"values_count": len(map_values),
"remainder_length": len(remainder_bytes),
"error_count": len(errs),
}).Debug("Finished reading MappingValues")
return
}

View File

@@ -2,8 +2,9 @@ package data
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
@@ -31,23 +32,34 @@ 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")
err = errors.New("error parsing string: zero length")
return
}
l, _, _ := NewInteger(str, 1)
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()
str_len := len(str) - 1
if length != str_len {
log.WithFields(log.Fields{
str_len := len(str)
if length > str_len {
/*log.WithFields(log.Fields{
"at": "(I2PString) Length",
"string_bytes_length": str_len,
"string_length_field": length,
"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",
}).Error("string format warning")
}).Warn("string format warning")
err = errors.New("string parsing warning: string data is shorter than specified by length")
}
return
@@ -60,28 +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":
data = string(str[1:])
return
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,
@@ -93,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
}
@@ -105,21 +134,37 @@ 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()
str = data[:data_len+1]
remainder = data[data_len+1:]
_, err = str.Length()
data_len := length.Int() + 1
str = data[:data_len]
remainder = data[data_len:]
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
}
// NewI2PString creates a new *I2PString from []byte using ReadI2PString.
// Returns a pointer to I2PString unlike ReadI2PString.
func NewI2PString(data []byte) (str *I2PString, remainder []byte, err error) {
/*func NewI2PString(data []byte) (str *I2PString, remainder []byte, err error) {
objstr, remainder, err := ReadI2PString(data)
str = &objstr
return
}
}*/

View File

@@ -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
@@ -26,39 +31,55 @@ Identical to KeysAndCert.
//
// https://geti2p.net/spec/common-structures#destination
type Destination struct {
*KeysAndCert
KeysAndCert
}
// 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) {
keys_and_cert, remainder, err := NewKeysAndCert(data)
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
}
// NewDestination creates a new *Destination from []byte using ReadDestination.
// Returns a pointer to Destination unlike ReadDestination.
func NewDestination(data []byte) (destination *Destination, remainder []byte, err error) {
objdestination, remainder, err := ReadDestination(data)
destination = &objdestination
return destination, remainder, err
}

View File

@@ -0,0 +1,42 @@
# destination
--
import "github.com/go-i2p/go-i2p/lib/common/destination"
Package destination implements the I2P Destination common data structure
## Usage
#### type Destination
```go
type Destination struct {
KeysAndCert
}
```
Destination is the represenation of an I2P Destination.
https://geti2p.net/spec/common-structures#destination
#### func ReadDestination
```go
func ReadDestination(data []byte) (destination Destination, remainder []byte, err error)
```
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 (Destination) Base32Address
```go
func (destination Destination) Base32Address() (str string)
```
Base32Address returns the I2P base32 address for this Destination.
#### func (Destination) Base64
```go
func (destination Destination) Base64() string
```
Base64 returns the I2P base64 address for this Destination.

View File

@@ -0,0 +1,12 @@
# exportable
--
import "github.com/go-i2p/go-i2p/lib/common/fuzz/certificate"
## Usage
#### func Fuzz
```go
func Fuzz(data []byte) int
```

View File

@@ -0,0 +1,12 @@
# exportable
--
import "github.com/go-i2p/go-i2p/lib/common/fuzz/destination"
## Usage
#### func Fuzz
```go
func Fuzz(data []byte) int
```

View File

@@ -0,0 +1,12 @@
# exportable
--
import "github.com/go-i2p/go-i2p/lib/common/fuzz/keys_and_cert"
## Usage
#### func Fuzz
```go
func Fuzz(data []byte) int
```

View File

@@ -3,7 +3,7 @@ package exportable
import common "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
func Fuzz(data []byte) int {
keys_and_cert, _, _ := common.NewKeysAndCert(data)
keys_and_cert, _, _ := common.ReadKeysAndCert(data)
keys_and_cert.Certificate()
keys_and_cert.PublicKey()
keys_and_cert.SigningPublicKey()

View File

@@ -0,0 +1,12 @@
# exportable
--
import "github.com/go-i2p/go-i2p/lib/common/fuzz/router_address"
## Usage
#### func Fuzz
```go
func Fuzz(data []byte) int
```

View File

@@ -0,0 +1,12 @@
# exportable
--
import "github.com/go-i2p/go-i2p/lib/common/fuzz/router_identity"
## Usage
#### func Fuzz
```go
func Fuzz(data []byte) int
```

View File

@@ -0,0 +1,12 @@
# exportable
--
import "github.com/go-i2p/go-i2p/lib/common/fuzz/string"
## Usage
#### func Fuzz
```go
func Fuzz(data []byte) int
```

View File

@@ -0,0 +1,154 @@
# key_certificate
--
import "github.com/go-i2p/go-i2p/lib/common/key_certificate"
Package key_certificate implements the I2P Destination common data structure
## Usage
```go
const (
KEYCERT_SIGN_DSA_SHA1 = iota
KEYCERT_SIGN_P256
KEYCERT_SIGN_P384
KEYCERT_SIGN_P521
KEYCERT_SIGN_RSA2048
KEYCERT_SIGN_RSA3072
KEYCERT_SIGN_RSA4096
KEYCERT_SIGN_ED25519
KEYCERT_SIGN_ED25519PH
)
```
Key Certificate Signing Key Types
```go
const (
KEYCERT_CRYPTO_ELG = iota
KEYCERT_CRYPTO_P256
KEYCERT_CRYPTO_P384
KEYCERT_CRYPTO_P521
KEYCERT_CRYPTO_X25519
)
```
Key Certificate Public Key Types
```go
const (
KEYCERT_SIGN_DSA_SHA1_SIZE = 128
KEYCERT_SIGN_P256_SIZE = 64
KEYCERT_SIGN_P384_SIZE = 96
KEYCERT_SIGN_P521_SIZE = 132
KEYCERT_SIGN_RSA2048_SIZE = 256
KEYCERT_SIGN_RSA3072_SIZE = 384
KEYCERT_SIGN_RSA4096_SIZE = 512
KEYCERT_SIGN_ED25519_SIZE = 32
KEYCERT_SIGN_ED25519PH_SIZE = 32
)
```
SigningPublicKey sizes for Signing Key Types
```go
const (
KEYCERT_CRYPTO_ELG_SIZE = 256
KEYCERT_CRYPTO_P256_SIZE = 64
KEYCERT_CRYPTO_P384_SIZE = 96
KEYCERT_CRYPTO_P521_SIZE = 132
KEYCERT_CRYPTO_X25519_SIZE = 32
)
```
PublicKey sizes for Public Key Types
```go
const (
KEYCERT_PUBKEY_SIZE = 256
KEYCERT_SPK_SIZE = 128
)
```
Sizes of structures in KeyCertificates
```go
const (
KEYCERT_MIN_SIZE = 7
)
```
#### type KeyCertificate
```go
type KeyCertificate struct {
Certificate
}
```
type KeyCertificate []byte
#### func KeyCertificateFromCertificate
```go
func KeyCertificateFromCertificate(certificate Certificate) *KeyCertificate
```
KeyCertificateFromCertificate returns a *KeyCertificate from a *Certificate.
#### func NewKeyCertificate
```go
func NewKeyCertificate(bytes []byte) (key_certificate *KeyCertificate, remainder []byte, err error)
```
NewKeyCertificate creates a new *KeyCertificate from []byte using
ReadCertificate. The remaining bytes after the specified length are also
returned. Returns a list of errors that occurred during parsing.
#### func (KeyCertificate) ConstructPublicKey
```go
func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_key crypto.PublicKey, err error)
```
ConstructPublicKey returns a PublicKey constructed using any excess data that
may be stored in the KeyCertififcate. Returns enr errors encountered while
parsing.
#### func (KeyCertificate) ConstructSigningPublicKey
```go
func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (signing_public_key crypto.SigningPublicKey, err error)
```
ConstructSigningPublicKey returns a SingingPublicKey constructed using any
excess data that may be stored in the KeyCertificate. Returns any errors
encountered while parsing.
#### func (KeyCertificate) CryptoSize
```go
func (key_certificate KeyCertificate) CryptoSize() (size int)
```
CryptoSize return the size of a Public Key corresponding to the Key
Certificate's PublicKey type.
#### func (KeyCertificate) Data
```go
func (key_certificate KeyCertificate) Data() ([]byte, error)
```
Data returns the raw []byte contained in the Certificate.
#### func (KeyCertificate) PublicKeyType
```go
func (key_certificate KeyCertificate) PublicKeyType() (pubkey_type int)
```
PublicKeyType returns the PublicKey type as a Go integer.
#### func (KeyCertificate) SignatureSize
```go
func (key_certificate KeyCertificate) SignatureSize() (size int)
```
SignatureSize return the size of a Signature corresponding to the Key
Certificate's SigningPublicKey type.
#### func (KeyCertificate) SigningPublicKeyType
```go
func (key_certificate KeyCertificate) SigningPublicKeyType() (signing_pubkey_type int)
```
SigningPublicKeyType returns the SigningPublicKey type as a Go integer.

View File

@@ -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
@@ -92,36 +96,51 @@ const (
// type KeyCertificate []byte
type KeyCertificate struct {
*Certificate
Certificate
spkType Integer
cpkType Integer
}
// 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
// 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,25 +291,49 @@ 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) {
var certificate *Certificate
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,
spkType: Integer(bytes[4:5]),
cpkType: Integer(bytes[6:7]),
}
remainder = bytes[KEYCERT_MIN_SIZE:]
if len(bytes) >= 5 {
key_certificate.spkType = Integer(bytes[4:5])
}
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())
func KeyCertificateFromCertificate(certificate Certificate) *KeyCertificate {
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
}

View File

@@ -0,0 +1,85 @@
# keys_and_cert
--
import "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
Package keys_and_cert implements the I2P KeysAndCert common data structure
## Usage
```go
const (
KEYS_AND_CERT_PUBKEY_SIZE = 256
KEYS_AND_CERT_SPK_SIZE = 128
KEYS_AND_CERT_MIN_SIZE = 387
KEYS_AND_CERT_DATA_SIZE = 384
)
```
Sizes of various KeysAndCert structures and requirements
#### type KeysAndCert
```go
type KeysAndCert struct {
KeyCertificate *KeyCertificate
}
```
KeysAndCert is the represenation of an I2P KeysAndCert.
https://geti2p.net/spec/common-structures#keysandcert
#### func ReadKeysAndCert
```go
func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte, err error)
```
ReadKeysAndCert creates a new *KeysAndCert from []byte using ReadKeysAndCert.
Returns a pointer to KeysAndCert unlike ReadKeysAndCert.
#### func (KeysAndCert) Bytes
```go
func (keys_and_cert KeysAndCert) Bytes() []byte
```
Bytes returns the entire KeyCertificate in []byte form, trims payload to
specified length.
#### func (*KeysAndCert) Certificate
```go
func (keys_and_cert *KeysAndCert) Certificate() (cert Certificate)
```
Certfificate returns the certificate.
#### func (*KeysAndCert) PublicKey
```go
func (keys_and_cert *KeysAndCert) PublicKey() (key crypto.PublicKey)
```
PublicKey returns the public key as a crypto.PublicKey.
#### func (*KeysAndCert) SigningPublicKey
```go
func (keys_and_cert *KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey)
```
SigningPublicKey returns the signing public key.
#### type PrivateKeysAndCert
```go
type PrivateKeysAndCert struct {
KeysAndCert
PK_KEY crypto.PrivateKey
SPK_KEY crypto.PrivateKey
}
```
PrivateKeysAndCert contains a KeysAndCert along with the corresponding private
keys for the Public Key and the Signing Public Key
#### func NewPrivateKeysAndCert
```go
func NewPrivateKeysAndCert() (*PrivateKeysAndCert, error)
```

View File

@@ -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
@@ -79,99 +83,40 @@ 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()
func (keys_and_cert KeysAndCert) Bytes() []byte {
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.
func (keys_and_cert *KeysAndCert) PublicKey() (key crypto.PublicKey) {
/*cert := keys_and_cert.Certificate()
cert_len := cert.Length()
if err != nil {
return
}
if cert_len == 0 {
// No Certificate is present, return the KEYS_AND_CERT_PUBKEY_SIZE byte
// PublicKey space as ElgPublicKey.
var elg_key crypto.ElgPublicKey
copy(keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE], elg_key[:])
key = elg_key
} else {
// A Certificate is present in this KeysAndCert
cert_type := cert.Type()
if cert_type == CERT_KEY {
// This KeysAndCert contains a Key Certificate, construct
// a PublicKey from the data in the KeysAndCert and
// any additional data in the Certificate.
key, err = KeyCertificateFromCertificate(cert).ConstructPublicKey(
keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE],
)
} else {
// Key Certificate is not present, return the KEYS_AND_CERT_PUBKEY_SIZE byte
// PublicKey space as ElgPublicKey. No other Certificate
// types are currently in use.
var elg_key crypto.ElgPublicKey
copy(keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE], elg_key[:])
key = elg_key
log.WithFields(log.Fields{
"at": "(KeysAndCert) PublicKey",
"cert_type": cert_type,
}).Warn("unused certificate type observed")
}
}
return*/
return keys_and_cert.publicKey
}
// SigningPublicKey returns the signing public key.
func (keys_and_cert *KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey) {
/*cert := keys_and_cert.Certificate()
cert_len := cert.Length()
if err != nil {
return
}
if cert_len == 0 {
// No Certificate is present, return the KEYS_AND_CERT_SPK_SIZE byte
// SigningPublicKey space as legacy DSA SHA1 SigningPublicKey.
var dsa_pk crypto.DSAPublicKey
copy(dsa_pk[:], keys_and_cert[KEYS_AND_CERT_PUBKEY_SIZE:KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE])
signing_public_key = dsa_pk
} else {
// A Certificate is present in this KeysAndCert
cert_type := cert.Type()
if cert_type == CERT_KEY {
// This KeysAndCert contains a Key Certificate, construct
// a SigningPublicKey from the data in the KeysAndCert and
// any additional data in the Certificate.
signing_public_key, err = KeyCertificateFromCertificate(cert).ConstructSigningPublicKey(
keys_and_cert[KEYS_AND_CERT_PUBKEY_SIZE : KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE],
)
} else {
// Key Certificate is not present, return the KEYS_AND_CERT_SPK_SIZE byte
// SigningPublicKey space as legacy SHA DSA1 SigningPublicKey.
// No other Certificate types are currently in use.
var dsa_pk crypto.DSAPublicKey
copy(dsa_pk[:], keys_and_cert[KEYS_AND_CERT_PUBKEY_SIZE:KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE])
signing_public_key = dsa_pk
}
}*/
return keys_and_cert.signingPublicKey
}
// Certfificate returns the certificate.
func (keys_and_cert *KeysAndCert) Certificate() (cert *Certificate) {
func (keys_and_cert *KeysAndCert) Certificate() (cert Certificate) {
return keys_and_cert.KeyCertificate.Certificate
}
// NewKeysAndCert creates a new *KeysAndCert from []byte using ReadKeysAndCert.
// ReadKeysAndCert creates a new *KeysAndCert from []byte using ReadKeysAndCert.
// Returns a pointer to KeysAndCert unlike ReadKeysAndCert.
func NewKeysAndCert(data []byte) (keys_and_cert *KeysAndCert, remainder []byte, err error) {
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{}
// 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,
@@ -181,7 +126,7 @@ func NewKeysAndCert(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,
@@ -192,20 +137,31 @@ func NewKeysAndCert(data []byte) (keys_and_cert *KeysAndCert, remainder []byte,
}
keys_and_cert.KeyCertificate, remainder, err = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
if err != nil {
return nil, nil, err
log.WithError(err).Error("Failed to create KeyCertificate")
return
}
// TODO: this only supports one key type right now and it's the old key type, but the layout is the same.
// a case-switch which sets the size of the SPK and the PK should be used to replace the referenced KEYS_AND_CERT_PUBKEY_SIZE
// and KEYS_AND_CERT_SPK_SIZE constants in the future.
keys_and_cert.publicKey, err = keys_and_cert.KeyCertificate.ConstructPublicKey(data[:keys_and_cert.KeyCertificate.CryptoSize()])
if err != nil {
return nil, nil, err
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 {
return nil, nil, err
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
return keys_and_cert, remainder, err
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
}

View File

@@ -24,7 +24,7 @@ func TestCertificateWithValidData(t *testing.T) {
cert_data := []byte{0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00}
data := make([]byte, 128+256)
data = append(data, cert_data...)
keys_and_cert, _, err := NewKeysAndCert(data)
keys_and_cert, _, err := ReadKeysAndCert(data)
assert.Nil(err)
cert := keys_and_cert.Certificate()
@@ -43,7 +43,7 @@ func TestPublicKeyWithBadData(t *testing.T) {
data := make([]byte, 128)
data = append(data, pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := NewKeysAndCert(data)
keys_and_cert, _, err := ReadKeysAndCert(data)
pub_key := keys_and_cert.PublicKey()
if assert.NotNil(err) {
@@ -60,7 +60,7 @@ func TestPublicKeyWithBadCertificate(t *testing.T) {
data := make([]byte, 128)
data = append(data, pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := NewKeysAndCert(data)
keys_and_cert, _, err := ReadKeysAndCert(data)
pub_key := keys_and_cert.PublicKey()
if assert.NotNil(err) {
@@ -77,7 +77,7 @@ func TestPublicKeyWithNullCertificate(t *testing.T) {
data := make([]byte, 128)
data = append(data, pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := NewKeysAndCert(data)
keys_and_cert, _, err := ReadKeysAndCert(data)
pub_key := keys_and_cert.PublicKey()
assert.Nil(err)
@@ -92,7 +92,7 @@ func TestPublicKeyWithKeyCertificate(t *testing.T) {
data := make([]byte, 128)
data = append(data, pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := NewKeysAndCert(data)
keys_and_cert, _, err := ReadKeysAndCert(data)
pub_key := keys_and_cert.PublicKey()
assert.Nil(err)
@@ -107,7 +107,7 @@ func TestSigningPublicKeyWithBadData(t *testing.T) {
data := make([]byte, 93)
data = append(data, pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := NewKeysAndCert(data)
keys_and_cert, _, err := ReadKeysAndCert(data)
signing_pub_key := keys_and_cert.SigningPublicKey()
if assert.NotNil(err) {
@@ -124,7 +124,7 @@ func TestSigningPublicKeyWithBadCertificate(t *testing.T) {
data := make([]byte, 128)
data = append(data, pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := NewKeysAndCert(data)
keys_and_cert, _, err := ReadKeysAndCert(data)
signing_pub_key := keys_and_cert.SigningPublicKey()
if assert.NotNil(err) {
@@ -141,7 +141,7 @@ func TestSigningPublicKeyWithNullCertificate(t *testing.T) {
signing_pub_key_data := make([]byte, 128)
data := append(pub_key_data, signing_pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := NewKeysAndCert(data)
keys_and_cert, _, err := ReadKeysAndCert(data)
signing_pub_key := keys_and_cert.SigningPublicKey()
assert.Nil(err)
@@ -156,7 +156,7 @@ func TestSigningPublicKeyWithKeyCertificate(t *testing.T) {
signing_pub_key_data := make([]byte, 128)
data := append(pub_key_data, signing_pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := NewKeysAndCert(data)
keys_and_cert, _, err := ReadKeysAndCert(data)
signing_pub_key := keys_and_cert.SigningPublicKey()
assert.Nil(err)
@@ -167,12 +167,11 @@ func TestNewKeysAndCertWithMissingData(t *testing.T) {
assert := assert.New(t)
cert_data := make([]byte, 128)
_, remainder, err := NewKeysAndCert(cert_data)
_, remainder, err := ReadKeysAndCert(cert_data)
assert.Equal(0, len(remainder))
if assert.NotNil(err) {
assert.Equal("error parsing KeysAndCert: data is smaller than minimum valid size", err.Error())
}
}
func TestNewKeysAndCertWithMissingCertData(t *testing.T) {
@@ -180,7 +179,7 @@ func TestNewKeysAndCertWithMissingCertData(t *testing.T) {
cert_data := make([]byte, 128+256)
cert_data = append(cert_data, []byte{0x05, 0x00, 0x04, 0x00, 0x01}...)
_, remainder, err := NewKeysAndCert(cert_data)
_, remainder, err := ReadKeysAndCert(cert_data)
assert.Equal(0, len(remainder))
if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error())
@@ -192,7 +191,7 @@ func TestNewKeysAndCertWithValidDataWithCertificate(t *testing.T) {
cert_data := make([]byte, 128+256)
cert_data = append(cert_data, []byte{0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00}...)
_, remainder, err := NewKeysAndCert(cert_data)
_, remainder, err := ReadKeysAndCert(cert_data)
assert.Equal(0, len(remainder))
assert.Nil(err)
}
@@ -202,7 +201,7 @@ func TestNewKeysAndCertWithValidDataWithoutCertificate(t *testing.T) {
cert_data := make([]byte, 128+256)
cert_data = append(cert_data, []byte{0x00, 0x00, 0x00}...)
_, remainder, err := NewKeysAndCert(cert_data)
_, remainder, err := ReadKeysAndCert(cert_data)
assert.Equal(0, len(remainder))
assert.Nil(err)
}
@@ -212,7 +211,7 @@ func TestNewKeysAndCertWithValidDataWithCertificateAndRemainder(t *testing.T) {
cert_data := make([]byte, 128+256)
cert_data = append(cert_data, []byte{0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x41}...)
_, remainder, err := NewKeysAndCert(cert_data)
_, remainder, err := ReadKeysAndCert(cert_data)
if assert.Equal(1, len(remainder)) {
assert.Equal("A", string(remainder[0]))
}
@@ -224,7 +223,7 @@ func TestNewKeysAndCertWithValidDataWithoutCertificateAndRemainder(t *testing.T)
cert_data := make([]byte, 128+256)
cert_data = append(cert_data, []byte{0x00, 0x00, 0x00, 0x41}...)
_, remainder, err := NewKeysAndCert(cert_data)
_, remainder, err := ReadKeysAndCert(cert_data)
if assert.Equal(1, len(remainder)) {
assert.Equal("A", string(remainder[0]))
}

View File

@@ -0,0 +1,18 @@
package keys_and_cert
import "crypto"
// PrivateKeysAndCert contains a KeysAndCert along with the corresponding private keys for the
// Public Key and the Signing Public Key
type PrivateKeysAndCert struct {
KeysAndCert
PK_KEY crypto.PrivateKey
SPK_KEY crypto.PrivateKey
}
func NewPrivateKeysAndCert() (*PrivateKeysAndCert, error) {
var pkc PrivateKeysAndCert
var err error
// pkc.PK_KEY, err =
return &pkc, err
}

63
lib/common/lease/doc.md Normal file
View File

@@ -0,0 +1,63 @@
# lease
--
import "github.com/go-i2p/go-i2p/lib/common/lease"
Package lease implements the I2P lease common data structure
## Usage
```go
const (
LEASE_SIZE = 44
LEASE_HASH_SIZE = 32
LEASE_TUNNEL_ID_SIZE = 4
)
```
Sizes in bytes of various components of a Lease
#### type Lease
```go
type Lease [LEASE_SIZE]byte
```
Lease is the represenation of an I2P Lease.
https://geti2p.net/spec/common-structures#lease
#### func NewLease
```go
func NewLease(data []byte) (lease *Lease, remainder []byte, err error)
```
NewLease creates a new *NewLease from []byte using ReadLease. Returns a pointer
to KeysAndCert unlike ReadLease.
#### func ReadLease
```go
func ReadLease(data []byte) (lease Lease, remainder []byte, err error)
```
ReadLease returns Lease from a []byte. The remaining bytes after the specified
length are also returned. Returns a list of errors that occurred during parsing.
#### func (Lease) Date
```go
func (lease Lease) Date() (date Date)
```
Date returns the date as an I2P Date.
#### func (Lease) TunnelGateway
```go
func (lease Lease) TunnelGateway() (hash Hash)
```
TunnelGateway returns the tunnel gateway as a Hash.
#### func (Lease) TunnelID
```go
func (lease Lease) TunnelID() uint32
```
TunnelID returns the tunnel id as a uint23.

View File

@@ -0,0 +1,95 @@
# lease_set
--
import "github.com/go-i2p/go-i2p/lib/common/lease_set"
Package lease_set implements the I2P LeastSet common data structure
## Usage
```go
const (
LEASE_SET_PUBKEY_SIZE = 256
LEASE_SET_SPK_SIZE = 128
LEASE_SET_SIG_SIZE = 40
)
```
Sizes of various structures in an I2P LeaseSet
#### type LeaseSet
```go
type LeaseSet []byte
```
LeaseSet is the represenation of an I2P LeaseSet.
https://geti2p.net/spec/common-structures#leaseset
#### func (LeaseSet) Destination
```go
func (lease_set LeaseSet) Destination() (destination Destination, err error)
```
Destination returns the Destination as []byte.
#### func (LeaseSet) LeaseCount
```go
func (lease_set LeaseSet) LeaseCount() (count int, err error)
```
LeaseCount returns the numbert of leases specified by the LeaseCount value as
int. returns errors encountered during parsing.
#### func (LeaseSet) Leases
```go
func (lease_set LeaseSet) Leases() (leases []Lease, err error)
```
Leases returns the leases as []Lease. returns errors encountered during parsing.
#### func (LeaseSet) NewestExpiration
```go
func (lease_set LeaseSet) NewestExpiration() (newest Date, err error)
```
NewestExpiration returns the newest lease expiration as an I2P Date. Returns
errors encountered during parsing.
#### func (LeaseSet) OldestExpiration
```go
func (lease_set LeaseSet) OldestExpiration() (earliest Date, err error)
```
OldestExpiration returns the oldest lease expiration as an I2P Date. Returns
errors encountered during parsing.
#### func (LeaseSet) PublicKey
```go
func (lease_set LeaseSet) PublicKey() (public_key crypto.ElgPublicKey, err error)
```
PublicKey returns the public key as crypto.ElgPublicKey. Returns errors
encountered during parsing.
#### func (LeaseSet) Signature
```go
func (lease_set LeaseSet) Signature() (signature Signature, err error)
```
Signature returns the signature as Signature. returns errors encountered during
parsing.
#### func (LeaseSet) SigningKey
```go
func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicKey, err error)
```
SigningKey returns the signing public key as crypto.SigningPublicKey. returns
errors encountered during parsing.
#### func (LeaseSet) Verify
```go
func (lease_set LeaseSet) Verify() error
```
Verify returns nil

View File

@@ -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
@@ -132,21 +136,27 @@ type LeaseSet struct {
// Destination returns the Destination as []byte.
func (lease_set LeaseSet) Destination() (destination Destination, err error) {
keys_and_cert, _, err := NewKeysAndCert(lease_set)
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
}
// PublicKey returns the public key as crypto.ElgPublicKey.
// Returns errors encountered during parsing.
func (lease_set LeaseSet) PublicKey() (public_key crypto.ElgPublicKey, err error) {
_, remainder, err := NewKeysAndCert(lease_set)
_, 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) {
_, remainder, err := NewKeysAndCert(lease_set)
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
}

View File

@@ -14,9 +14,9 @@ import (
func buildDestination() *router_identity.RouterIdentity {
router_ident_data := make([]byte, 128+256)
router_ident_data = append(router_ident_data, []byte{0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00}...)
ident, _, err := router_identity.NewRouterIdentity(router_ident_data)
ident, _, err := router_identity.ReadRouterIdentity(router_ident_data)
panic(err)
return ident
return &ident
}
func buildPublicKey() []byte {
@@ -77,7 +77,7 @@ func TestDestinationIsCorrect(t *testing.T) {
dest, err := lease_set.Destination()
assert.Nil(err)
dest_cert := dest.Certificate()
//assert.Nil(err)
// assert.Nil(err)
cert_type := dest_cert.Type()
assert.Nil(err)
assert.Equal(certificate.CERT_KEY, cert_type)

View File

@@ -0,0 +1,192 @@
# router_address
--
import "github.com/go-i2p/go-i2p/lib/common/router_address"
Package router_address implements the I2P RouterAddress common data structure
## Usage
```go
const (
ROUTER_ADDRESS_MIN_SIZE = 9
)
```
Minimum number of bytes in a valid RouterAddress
#### type RouterAddress
```go
type RouterAddress struct {
TransportCost *Integer
ExpirationDate *Date
TransportType I2PString
TransportOptions *Mapping
}
```
RouterAddress is the represenation of an I2P RouterAddress.
https://geti2p.net/spec/common-structures#routeraddress
#### func ReadRouterAddress
```go
func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []byte, err error)
```
ReadRouterAddress returns RouterAddress from a []byte. The remaining bytes after
the specified length are also returned. Returns a list of errors that occurred
during parsing.
#### func (RouterAddress) Bytes
```go
func (router_address RouterAddress) Bytes() []byte
```
Bytes returns the router address as a []byte.
#### func (RouterAddress) CapsString
```go
func (router_address RouterAddress) CapsString() I2PString
```
#### func (RouterAddress) Cost
```go
func (router_address RouterAddress) Cost() int
```
Cost returns the cost for this RouterAddress as a Go integer.
#### func (RouterAddress) Expiration
```go
func (router_address RouterAddress) Expiration() Date
```
Expiration returns the expiration for this RouterAddress as an I2P Date.
#### func (RouterAddress) GetOption
```go
func (router_address RouterAddress) GetOption(key I2PString) I2PString
```
GetOption returns the value of the option specified by the key
#### func (RouterAddress) Host
```go
func (router_address RouterAddress) Host() (net.Addr, error)
```
#### func (RouterAddress) HostString
```go
func (router_address RouterAddress) HostString() I2PString
```
#### func (*RouterAddress) IPVersion
```go
func (router_address *RouterAddress) IPVersion() string
```
IPVersion returns a string "4" for IPv4 or 6 for IPv6
#### func (RouterAddress) InitializationVector
```go
func (router_address RouterAddress) InitializationVector() ([32]byte, error)
```
#### func (RouterAddress) InitializationVectorString
```go
func (router_address RouterAddress) InitializationVectorString() I2PString
```
#### func (RouterAddress) IntroducerExpirationString
```go
func (router_address RouterAddress) IntroducerExpirationString(num int) I2PString
```
#### func (RouterAddress) IntroducerHashString
```go
func (router_address RouterAddress) IntroducerHashString(num int) I2PString
```
#### func (RouterAddress) IntroducerTagString
```go
func (router_address RouterAddress) IntroducerTagString(num int) I2PString
```
#### func (*RouterAddress) Network
```go
func (router_address *RouterAddress) Network() string
```
Network implements net.Addr. It returns the transport type plus 4 or 6
#### func (RouterAddress) Options
```go
func (router_address RouterAddress) Options() Mapping
```
Options returns the options for this RouterAddress as an I2P Mapping.
#### func (RouterAddress) Port
```go
func (router_address RouterAddress) Port() (string, error)
```
#### func (RouterAddress) PortString
```go
func (router_address RouterAddress) PortString() I2PString
```
#### func (RouterAddress) ProtocolVersion
```go
func (router_address RouterAddress) ProtocolVersion() (string, error)
```
#### func (RouterAddress) ProtocolVersionString
```go
func (router_address RouterAddress) ProtocolVersionString() I2PString
```
#### func (RouterAddress) StaticKey
```go
func (router_address RouterAddress) StaticKey() ([32]byte, error)
```
#### func (RouterAddress) StaticKeyString
```go
func (router_address RouterAddress) StaticKeyString() I2PString
```
#### func (*RouterAddress) String
```go
func (router_address *RouterAddress) String() string
```
String implements net.Addr. It returns the IP address, followed by the options
#### func (RouterAddress) TransportStyle
```go
func (router_address RouterAddress) TransportStyle() I2PString
```
TransportStyle returns the transport style for this RouterAddress as an
I2PString.
#### func (*RouterAddress) UDP
```go
func (router_address *RouterAddress) UDP() bool
```

View File

@@ -3,9 +3,15 @@ package router_address
import (
"errors"
"fmt"
"net"
"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
@@ -13,6 +19,8 @@ const (
ROUTER_ADDRESS_MIN_SIZE = 9
)
var log = logger.GetGoI2PLogger()
/*
[RouterAddress]
Accurate for version 0.9.49
@@ -63,47 +71,245 @@ options :: Mapping
//
// https://geti2p.net/spec/common-structures#routeraddress
type RouterAddress struct {
cost *Integer
expiration *Date
transport_style *I2PString
options *Mapping
TransportCost *Integer
ExpirationDate *Date
TransportType I2PString
TransportOptions *Mapping
}
// 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 ""
}
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")
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()))
rv = append(rv, string(router_address.PortString()))
rv = append(rv, string(router_address.StaticKeyString()))
rv = append(rv, string(router_address.InitializationVectorString()))
rv = append(rv, string(router_address.ProtocolVersionString()))
if router_address.UDP() {
rv = append(rv, string(router_address.IntroducerHashString(0)))
rv = append(rv, string(router_address.IntroducerExpirationString(0)))
rv = append(rv, string(router_address.IntroducerTagString(0)))
rv = append(rv, string(router_address.IntroducerHashString(1)))
rv = append(rv, string(router_address.IntroducerExpirationString(1)))
rv = append(rv, string(router_address.IntroducerTagString(1)))
rv = append(rv, string(router_address.IntroducerHashString(2)))
rv = append(rv, string(router_address.IntroducerExpirationString(2)))
rv = append(rv, string(router_address.IntroducerTagString(2)))
}
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.cost.Bytes()...)
bytes = append(bytes, router_address.expiration.Bytes()...)
strData, err := router_address.transport_style.Data()
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.options.Data()...)
bytes = append(bytes, router_address.TransportOptions.Data()...)
log.WithField("bytes_length", len(bytes)).Debug("Converted RouterAddress to bytes")
return bytes
}
// Cost returns the cost for this RouterAddress as a Go integer.
func (router_address RouterAddress) Cost() int {
return router_address.cost.Int()
return router_address.TransportCost.Int()
}
// Expiration returns the expiration for this RouterAddress as an I2P Date.
func (router_address RouterAddress) Expiration() Date {
return *router_address.expiration
return *router_address.ExpirationDate
}
// TransportStyle returns the transport style for this RouterAddress as an I2PString.
func (router_address RouterAddress) TransportStyle() I2PString {
return *router_address.transport_style
return router_address.TransportType
}
// GetOption returns the value of the option specified by the key
func (router_address RouterAddress) GetOption(key I2PString) I2PString {
return router_address.Options().Values().Get(key)
}
func (router_address RouterAddress) HostString() I2PString {
host, _ := ToI2PString("host")
return router_address.GetOption(host)
}
func (router_address RouterAddress) PortString() I2PString {
port, _ := ToI2PString("port")
return router_address.GetOption(port)
}
func (router_address RouterAddress) CapsString() I2PString {
caps, _ := ToI2PString("caps")
return router_address.GetOption(caps)
}
func (router_address RouterAddress) StaticKeyString() I2PString {
sk, _ := ToI2PString("s")
return router_address.GetOption(sk)
}
func (router_address RouterAddress) InitializationVectorString() I2PString {
iv, _ := ToI2PString("i")
return router_address.GetOption(iv)
}
func (router_address RouterAddress) ProtocolVersionString() I2PString {
v, _ := ToI2PString("v")
return router_address.GetOption(v)
}
func (router_address RouterAddress) IntroducerHashString(num int) I2PString {
if num >= 0 && num <= 2 {
val := strconv.Itoa(num)
v, _ := ToI2PString("ih" + val)
return router_address.GetOption(v)
}
v, _ := ToI2PString("ih0")
return router_address.GetOption(v)
}
func (router_address RouterAddress) IntroducerExpirationString(num int) I2PString {
if num >= 0 && num <= 2 {
val := strconv.Itoa(num)
v, _ := ToI2PString("iexp" + val)
return router_address.GetOption(v)
}
v, _ := ToI2PString("iexp0")
return router_address.GetOption(v)
}
func (router_address RouterAddress) IntroducerTagString(num int) I2PString {
if num >= 0 && num <= 2 {
val := strconv.Itoa(num)
v, _ := ToI2PString("itag" + val)
return router_address.GetOption(v)
}
v, _ := ToI2PString("itag0")
return router_address.GetOption(v)
}
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())
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
portStr := strconv.Itoa(val)
log.WithField("port", portStr).Debug("Retrieved port from RouterAddress")
return portStr, nil
}
func (router_address RouterAddress) StaticKey() ([32]byte, error) {
sk := router_address.StaticKeyString()
if len([]byte(sk)) != 32 {
return [32]byte{}, fmt.Errorf("error: invalid static key")
}
return [32]byte(sk), nil
}
func (router_address RouterAddress) InitializationVector() ([32]byte, error) {
iv := router_address.InitializationVectorString()
if len([]byte(iv)) != 32 {
return [32]byte{}, fmt.Errorf("error: invalid static key")
}
return [32]byte(iv), nil
}
func (router_address RouterAddress) ProtocolVersion() (string, error) {
return router_address.ProtocolVersionString().Data()
}
// Options returns the options for this RouterAddress as an I2P Mapping.
func (router_address RouterAddress) Options() Mapping {
return *router_address.options
return *router_address.TransportOptions
}
// Check if the RouterAddress is empty or if it is too small to contain valid data.
@@ -115,48 +321,41 @@ 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")
return
}
router_address.cost, remainder, err = NewInteger(data, 1)
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.expiration, remainder, err = NewDate(remainder)
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.transport_style, remainder, err = NewI2PString(remainder)
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")
}
var errs []error
router_address.options, remainder, errs = NewMapping(remainder)
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,
}).Error("error parsing RouterAddress")
"error": err,
}).Error("error parsing RozuterAddress")
}
return
}
// NewRouterAddress creates a new *RouterAddress from []byte using ReadRouterAddress.
// Returns a pointer to RouterAddress unlike ReadRouterAddress.
func NewRouterAddress(data []byte) (router_address *RouterAddress, remainder []byte, err error) {
objrouteraddress, remainder, err := ReadRouterAddress(data)
router_address = &objrouteraddress
return
}

View File

@@ -31,7 +31,6 @@ func TestCheckRouterAddressValidReportsDataMissing(t *testing.T) {
err, exit := router_address.checkValid()
assert.Equal(exit, false, "checkValid indicates to stop parsing when some fields may be present")
}
func TestCheckRouterAddressValidNoErrWithValidData(t *testing.T) {
@@ -40,8 +39,8 @@ func TestCheckRouterAddressValidNoErrWithValidData(t *testing.T) {
router_address, _, _ := ReadRouterAddress([]byte{0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00})
mapping, err := GoMapToMapping(map[string]string{"host": "127.0.0.1", "port": "4567"})
assert.Nil(err, "GoMapToMapping() returned error with valid data")
router_address.options = mapping
//router_address = append(router_address, mapping...)
router_address.TransportOptions = mapping
// router_address = append(router_address, mapping...)
err, exit := router_address.checkValid()
assert.Nil(err, "checkValid() reported error with valid data")

View File

@@ -0,0 +1,28 @@
# router_identity
--
import "github.com/go-i2p/go-i2p/lib/common/router_identity"
Package router_identity implements the I2P RouterIdentity common data structure
## Usage
#### type RouterIdentity
```go
type RouterIdentity struct {
KeysAndCert
}
```
RouterIdentity is the represenation of an I2P RouterIdentity.
https://geti2p.net/spec/common-structures#routeridentity
#### func ReadRouterIdentity
```go
func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder []byte, err error)
```
ReadRouterIdentity returns RouterIdentity from a []byte. The remaining bytes
after the specified length are also returned. Returns a list of errors that
occurred during parsing.

View File

@@ -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
@@ -20,24 +24,26 @@ Identical to KeysAndCert.
//
// https://geti2p.net/spec/common-structures#routeridentity
type RouterIdentity struct {
*KeysAndCert
KeysAndCert
}
// ReadRouterIdentity returns RouterIdentity from a []byte.
// 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) {
keys_and_cert, remainder, err := NewKeysAndCert(data)
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,
}
return
}
// NewRouterIdentity creates a new *RouterIdentity from []byte using ReadRouterIdentity.
// Returns a pointer to RouterIdentity unlike ReadRouterIdentity.
func NewRouterIdentity(data []byte) (router_identity *RouterIdentity, remainder []byte, err error) {
objrouter_identity, remainder, err := ReadRouterIdentity(data)
router_identity = &objrouter_identity
log.WithFields(logrus.Fields{
"remainder_length": len(remainder),
}).Debug("Successfully read RouterIdentity")
return
}

View File

@@ -0,0 +1,146 @@
# router_info
--
import "github.com/go-i2p/go-i2p/lib/common/router_info"
Package router_info implements the I2P RouterInfo common data structure
## Usage
```go
const (
MIN_GOOD_VERSION = 58
MAX_GOOD_VERSION = 99
)
```
```go
const ROUTER_INFO_MIN_SIZE = 439
```
#### type RouterInfo
```go
type RouterInfo struct {
}
```
RouterInfo is the represenation of an I2P RouterInfo.
https://geti2p.net/spec/common-structures#routerinfo
#### func ReadRouterInfo
```go
func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
```
ReadRouterInfo returns RouterInfo from a []byte. The remaining bytes after the
specified length are also returned. Returns a list of errors that occurred
during parsing.
#### func (RouterInfo) Bytes
```go
func (router_info RouterInfo) Bytes() (bytes []byte, err error)
```
Bytes returns the RouterInfo as a []byte suitable for writing to a stream.
#### func (*RouterInfo) GoodVersion
```go
func (router_info *RouterInfo) GoodVersion() bool
```
#### func (*RouterInfo) IdentHash
```go
func (router_info *RouterInfo) IdentHash() Hash
```
IndentHash returns the identity hash (sha256 sum) for this RouterInfo.
#### func (RouterInfo) Network
```go
func (router_info RouterInfo) Network() string
```
Network implements net.Addr
#### func (RouterInfo) Options
```go
func (router_info RouterInfo) Options() (mapping Mapping)
```
Options returns the options for this RouterInfo as an I2P Mapping.
#### func (*RouterInfo) PeerSize
```go
func (router_info *RouterInfo) PeerSize() int
```
PeerSize returns the peer size as a Go integer.
#### func (*RouterInfo) Published
```go
func (router_info *RouterInfo) Published() *Date
```
Published returns the date this RouterInfo was published as an I2P Date.
#### func (*RouterInfo) Reachable
```go
func (router_info *RouterInfo) Reachable() bool
```
#### func (*RouterInfo) RouterAddressCount
```go
func (router_info *RouterInfo) RouterAddressCount() int
```
RouterAddressCount returns the count of RouterAddress in this RouterInfo as a Go
integer.
#### func (*RouterInfo) RouterAddresses
```go
func (router_info *RouterInfo) RouterAddresses() []*RouterAddress
```
RouterAddresses returns all RouterAddresses for this RouterInfo as
[]*RouterAddress.
#### func (*RouterInfo) RouterCapabilities
```go
func (router_info *RouterInfo) RouterCapabilities() string
```
#### func (*RouterInfo) RouterIdentity
```go
func (router_info *RouterInfo) RouterIdentity() *RouterIdentity
```
RouterIdentity returns the router identity as *RouterIdentity.
#### func (*RouterInfo) RouterVersion
```go
func (router_info *RouterInfo) RouterVersion() string
```
#### func (RouterInfo) Signature
```go
func (router_info RouterInfo) Signature() (signature Signature)
```
Signature returns the signature for this RouterInfo as an I2P Signature.
#### func (RouterInfo) String
```go
func (router_info RouterInfo) String() string
```
#### func (*RouterInfo) UnCongested
```go
func (router_info *RouterInfo) UnCongested() bool
```

View File

@@ -6,17 +6,23 @@ 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 MIN_GOOD_VERSION = 58
const MAX_GOOD_VERSION = 99
const (
MIN_GOOD_VERSION = 58
MAX_GOOD_VERSION = 99
)
/*
[RouterInfo]
@@ -102,7 +108,7 @@ signature :: Signature
//
// https://geti2p.net/spec/common-structures#routerinfo
type RouterInfo struct {
router_identity *RouterIdentity
router_identity RouterIdentity
published *Date
size *Integer
addresses []*RouterAddress
@@ -112,9 +118,8 @@ type RouterInfo struct {
}
// Bytes returns the RouterInfo as a []byte suitable for writing to a stream.
func (router_info RouterInfo) Bytes() ([]byte, error) {
var err error
var bytes []byte
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()...)
@@ -123,21 +128,38 @@ func (router_info RouterInfo) Bytes() ([]byte, error) {
}
bytes = append(bytes, router_info.peer_size.Bytes()...)
bytes = append(bytes, router_info.options.Data()...)
//bytes = append(bytes, []byte(*router_info.signature)...)
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())
for index, router_address := range router_info.addresses {
str += "Address " + strconv.Itoa(index) + ": " + router_address.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
}
// RouterIdentity returns the router identity as *RouterIdentity.
func (router_info *RouterInfo) RouterIdentity() *RouterIdentity {
return router_info.router_identity
return &router_info.router_identity
}
// IndentHash returns the identity hash (sha256 sum) for this RouterInfo.
func (router_info *RouterInfo) IdentHash() Hash {
ri := router_info.RouterIdentity()
h := HashData(ri.KeysAndCert.Certificate().Data())
return h
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)
}
// Published returns the date this RouterInfo was published as an I2P Date.
@@ -147,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
}
@@ -167,86 +192,36 @@ func (router_info RouterInfo) Options() (mapping Mapping) {
return *router_info.options
}
//
// Return the signature of this router info
//
// Signature returns the signature for this RouterInfo as an I2P Signature.
func (router_info RouterInfo) Signature() (signature Signature) {
return *router_info.signature
}
//
// Used during parsing to determine where in the RouterInfo the Mapping data begins.
//
/*func (router_info RouterInfo) optionsLocation() (location int) {
data, remainder, err := ReadRouterIdentity(router_info)
if err != nil {
return
}
location += len(data)
remainder_len := len(remainder)
if remainder_len < 9 {
log.WithFields(log.Fields{
"at": "(RouterInfo) optionsLocation",
"data_len": remainder_len,
"required_len": 9,
"reason": "not enough data",
}).Error("error parsing router info")
err = errors.New("error parsing router addresses: not enough data")
return
}
location += 9
remaining := remainder[9:]
var router_address RouterAddress
var router_addresses []RouterAddress
addr_count, cerr := router_info.RouterAddressCount()
if cerr != nil {
err = cerr
return
}
for i := 0; i < addr_count; i++ {
router_address, remaining, err = ReadRouterAddress(remaining)
if err == nil {
location += len(router_address)
router_addresses = append(router_addresses, router_address)
}
}
location += 1
return
}*/
//
// Used during parsing to determine the size of the options in the RouterInfo.
//
/*func (router_info RouterInfo) optionsSize() (size int) {
head := router_info.optionsLocation()
s := Integer(router_info[head : head+2])
size = s.Int() + 2
return
}*/
// Network implements net.Addr
func (router_info RouterInfo) Network() string {
return "i2p"
}
// ReadRouterInfo returns RouterInfo from a []byte.
// 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) {
identity, remainder, err := NewRouterIdentity(bytes)
info.router_identity = identity
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,
"reason": "not enough data",
}).Error("error parsing router info")
err = errors.New("error parsing router info: not enough data")
return
}
date, remainder, err := NewDate(remainder)
info.published = date
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,
@@ -254,30 +229,20 @@ 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")
}
size, remainder, err := NewInteger(remainder, 1)
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": size.Int(),
"required_len": info.size.Int(),
"reason": "read error",
}).Error("error parsing router info size")
}
info.size = size
if err != nil {
log.WithFields(log.Fields{
"at": "(RouterInfo) ReadRouterInfo",
"data_len": len(remainder),
"required_len": size.Int(),
"reason": "not enough data",
}).Error("error parsing router info")
err = errors.New("error parsing router info: not enough data")
}
for i := 0; i < size.Int(); i++ {
address, more, err := NewRouterAddress(remainder)
for i := 0; i < info.size.Int(); i++ {
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,
@@ -285,13 +250,17 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
}).Error("error parsing router address")
err = errors.New("error parsing router info: not enough data")
}
info.addresses = append(info.addresses, address)
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,
@@ -303,8 +272,9 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
}
err = errors.New("error parsing router info: " + estring)
}
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,
@@ -312,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" {
@@ -345,35 +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")
}
// NewRouterInfo creates a new *RouterInfo from []byte using ReadRouterInfo.
// Returns a pointer to RouterInfo unlike ReadRouterInfo.
func NewRouterInfo(data []byte) (router_info *RouterInfo, remainder []byte, err error) {
routerInfo, remainder, err := ReadRouterInfo(data)
router_info = &routerInfo
return
// 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
}

View File

@@ -131,7 +131,6 @@ func TestRouterAddressesReturnsAddresses(t *testing.T) {
),
)
}
}
func TestRouterAddressesReturnsAddressesWithMultiple(t *testing.T) {
@@ -162,7 +161,6 @@ func TestRouterAddressesReturnsAddressesWithMultiple(t *testing.T) {
)
}
}
}
func TestPeerSizeIsZero(t *testing.T) {
@@ -200,7 +198,7 @@ func TestRouterIdentityIsCorrect(t *testing.T) {
router_info, _ := buildFullRouterInfo()
router_identity := router_info.RouterIdentity()
//assert.Nil(err)
// assert.Nil(err)
assert.Equal(
0,
bytes.Compare(

View File

@@ -0,0 +1,34 @@
# session_key
--
import "github.com/go-i2p/go-i2p/lib/common/session_key"
Package session_key implements the I2P SessionKey common data structure
## Usage
#### type SessionKey
```go
type SessionKey [32]byte
```
SessionKey is the represenation of an I2P SessionKey.
https://geti2p.net/spec/common-structures#sessionkey
#### func NewSessionKey
```go
func NewSessionKey(data []byte) (session_key *SessionKey, remainder []byte, err error)
```
NewSessionKey creates a new *SessionKey from []byte using ReadSessionKey.
Returns a pointer to SessionKey unlike ReadSessionKey.
#### func ReadSessionKey
```go
func ReadSessionKey(bytes []byte) (info SessionKey, remainder []byte, err error)
```
ReadSessionKey returns SessionKey from a []byte. The remaining bytes after the
specified length are also returned. Returns a list of errors that occurred
during parsing.

View File

@@ -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
}

View File

@@ -0,0 +1,34 @@
# session_tag
--
import "github.com/go-i2p/go-i2p/lib/common/session_tag"
Package session_tag implements the I2P SessionTag common data structure
## Usage
#### type SessionTag
```go
type SessionTag [32]byte
```
SessionTag is the represenation of an I2P SessionTag.
https://geti2p.net/spec/common-structures#session-tag
#### func NewSessionTag
```go
func NewSessionTag(data []byte) (session_tag *SessionTag, remainder []byte, err error)
```
NewSessionTag creates a new *SessionTag from []byte using ReadSessionTag.
Returns a pointer to SessionTag unlike ReadSessionTag.
#### func ReadSessionTag
```go
func ReadSessionTag(bytes []byte) (info SessionTag, remainder []byte, err error)
```
ReadSessionTag returns SessionTag from a []byte. The remaining bytes after the
specified length are also returned. Returns a list of errors that occurred
during parsing.

View File

@@ -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
}

View File

@@ -0,0 +1,50 @@
# signature
--
import "github.com/go-i2p/go-i2p/lib/common/signature"
Package signature implements the I2P Signature common data structure
## Usage
```go
const (
DSA_SHA1_SIZE = 40
ECDSA_SHA256_P256_SIZE = 64
ECDSA_SHA384_P384_SIZE = 96
ECDSA_SHA512_P512_SIZE = 132
RSA_SHA256_2048_SIZE = 256
RSA_SHA384_3072_SIZE = 384
RSA_SHA512_4096_SIZE = 512
EdDSA_SHA512_Ed25519_SIZE = 64
EdDSA_SHA512_Ed25519ph_SIZE = 64
RedDSA_SHA512_Ed25519_SIZE = 64
)
```
Lengths of signature keys
#### type Signature
```go
type Signature []byte
```
Signature is the represenation of an I2P Signature.
https://geti2p.net/spec/common-structures#signature
#### func NewSignature
```go
func NewSignature(data []byte) (session_tag *Signature, remainder []byte, err error)
```
NewSignature creates a new *Signature from []byte using ReadSignature. Returns a
pointer to Signature unlike ReadSignature.
#### func ReadSignature
```go
func ReadSignature(bytes []byte) (info Signature, remainder []byte, err error)
```
ReadSignature returns Signature from a []byte. The remaining bytes after the
specified length are also returned. Returns a list of errors that occurred
during parsing.

View File

@@ -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
}

85
lib/config/doc.md Normal file
View File

@@ -0,0 +1,85 @@
# config
--
import "github.com/go-i2p/go-i2p/lib/config"
## Usage
```go
var DefaultBootstrapConfig = BootstrapConfig{
LowPeerThreshold: 10,
ReseedServers: []*ReseedConfig{},
}
```
default configuration for network bootstrap
```go
var DefaultNetDbConfig = NetDbConfig{
Path: filepath.Join(defaultConfig(), "netDb"),
}
```
default settings for netdb
```go
var RouterConfigProperties = DefaultRouterConfig()
```
#### type BootstrapConfig
```go
type BootstrapConfig struct {
// if we have less than this many peers we should reseed
LowPeerThreshold int
// reseed servers
ReseedServers []*ReseedConfig
}
```
#### type NetDbConfig
```go
type NetDbConfig struct {
// path to network database directory
Path string
}
```
local network database configuration
#### type ReseedConfig
```go
type ReseedConfig struct {
// url of reseed server
Url string
// fingerprint of reseed su3 signing key
SU3Fingerprint string
}
```
configuration for 1 reseed server
#### type RouterConfig
```go
type RouterConfig struct {
// the path to the base config directory where per-system defaults are stored
BaseDir string
// the path to the working config directory where files are changed
WorkingDir string
// netdb configuration
NetDb *NetDbConfig
// configuration for bootstrapping into the network
Bootstrap *BootstrapConfig
}
```
router.config options
#### func DefaultRouterConfig
```go
func DefaultRouterConfig() *RouterConfig
```

View File

@@ -12,5 +12,5 @@ type NetDbConfig struct {
// default settings for netdb
var DefaultNetDbConfig = NetDbConfig{
Path: filepath.Join(".", "netDb"),
Path: filepath.Join(defaultConfig(), "netDb"),
}

View File

@@ -1,15 +1,48 @@
package config
import (
"os"
"path/filepath"
)
// router.config options
type RouterConfig struct {
// the path to the base config directory where per-system defaults are stored
BaseDir string
// the path to the working config directory where files are changed
WorkingDir string
// netdb configuration
NetDb *NetDbConfig
// configuration for bootstrapping into the network
Bootstrap *BootstrapConfig
}
// defaults for router
var DefaultRouterConfig = &RouterConfig{
NetDb: &DefaultNetDbConfig,
Bootstrap: &DefaultBootstrapConfig,
func home() string {
h, err := os.UserHomeDir()
if err != nil {
panic(err)
}
return h
}
func defaultBase() string {
return filepath.Join(home(), "go-i2p", "base")
}
func defaultConfig() string {
return filepath.Join(home(), "go-i2p", "config")
}
// defaults for router
var defaultRouterConfig = &RouterConfig{
NetDb: &DefaultNetDbConfig,
Bootstrap: &DefaultBootstrapConfig,
BaseDir: defaultBase(),
WorkingDir: defaultConfig(),
}
func DefaultRouterConfig() *RouterConfig {
return defaultRouterConfig
}
var RouterConfigProperties = DefaultRouterConfig()

View File

@@ -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
View 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)
}
})
}
}

194
lib/crypto/curve25519.go Normal file
View File

@@ -0,0 +1,194 @@
package crypto
import (
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"errors"
"io"
"math/big"
"github.com/sirupsen/logrus"
curve25519 "go.step.sm/crypto/x25519"
)
var Curve25519EncryptTooBig = errors.New("failed to encrypt data, too big for Curve25519")
type Curve25519PublicKey []byte
type Curve25519Verifier struct {
k []byte
}
func (k Curve25519PublicKey) NewVerifier() (v Verifier, err error) {
temp := new(Curve25519Verifier)
temp.k = k
v = temp
return temp, nil
}
func (k Curve25519PublicKey) Len() int {
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
}
func createCurve25519Encryption(pub *curve25519.PublicKey, rand io.Reader) (enc *Curve25519Encryption, err error) {
/*kbytes := make([]byte, 256)
k := new(big.Int)
for err == nil {
_, err = io.ReadFull(rand, kbytes)
k = new(big.Int).SetBytes(kbytes)
k = k.Mod(k, pub.P)
if k.Sign() != 0 {
break
}
}
if err == nil {
enc = &Curve25519Encryption{}
}*/
log.Warn("createCurve25519Encryption is not implemented")
return
}
type Curve25519Encryption struct {
p, a, b1 *big.Int
}
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
}
mbytes := make([]byte, 255)
mbytes[0] = 0xFF
copy(mbytes[33:], data)
// do sha256 of payload
d := sha256.Sum256(mbytes[33 : len(data)+33])
copy(mbytes[1:], d[:])
m := new(big.Int).SetBytes(mbytes)
// do encryption
b := new(big.Int).Mod(new(big.Int).Mul(curve25519.b1, m), curve25519.p).Bytes()
if zeroPadding {
encrypted = make([]byte, 514)
copy(encrypted[1:], curve25519.a.Bytes())
copy(encrypted[258:], b)
} else {
encrypted = make([]byte, 512)
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
}
type Curve25519PrivateKey curve25519.PrivateKey
type Curve25519Signer struct {
k []byte
}
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) {
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
}

View File

@@ -8,7 +8,6 @@ type Decrypter interface {
}
type PrivateEncryptionKey interface {
// create a new decryption object for this private key to decrypt data encrypted to our public key
// returns decrypter or nil and error if the private key is in a bad format
NewDecrypter() (Decrypter, error)

801
lib/crypto/doc.md Normal file
View File

@@ -0,0 +1,801 @@
# crypto
--
import "github.com/go-i2p/go-i2p/lib/crypto"
package for i2p specific crpytography
## Usage
```go
const (
IPAD = byte(0x36)
OPAD = byte(0x5C)
)
```
```go
var (
ElgDecryptFail = errors.New("failed to decrypt elgamal encrypted data")
ElgEncryptTooBig = errors.New("failed to encrypt data, too big for elgamal")
)
```
```go
var (
ErrBadSignatureSize = errors.New("bad signature size")
ErrInvalidKeyFormat = errors.New("invalid key format")
ErrInvalidSignature = errors.New("invalid signature")
)
```
```go
var Curve25519EncryptTooBig = errors.New("failed to encrypt data, too big for Curve25519")
```
```go
var Ed25519EncryptTooBig = errors.New("failed to encrypt data, too big for Ed25519")
```
```go
var SHA256 = sha256.Sum256
```
#### func ElgamalGenerate
```go
func ElgamalGenerate(priv *elgamal.PrivateKey, rand io.Reader) (err error)
```
generate an elgamal key pair
#### 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
#### func (*AESSymmetricDecrypter) DecryptNoPadding
```go
func (d *AESSymmetricDecrypter) DecryptNoPadding(data []byte) ([]byte, error)
```
DecryptNoPadding decrypts data using AES-CBC without padding
#### 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
#### func (*AESSymmetricEncrypter) EncryptNoPadding
```go
func (e *AESSymmetricEncrypter) EncryptNoPadding(data []byte) ([]byte, error)
```
EncryptNoPadding encrypts data using AES-CBC without padding
#### 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) Len
```go
func (k *AESSymmetricKey) Len() int
```
Len returns the length of the key
#### func (*AESSymmetricKey) NewDecrypter
```go
func (k *AESSymmetricKey) NewDecrypter() (Decrypter, error)
```
NewDecrypter creates a new AESSymmetricDecrypter
#### func (*AESSymmetricKey) NewEncrypter
```go
func (k *AESSymmetricKey) NewEncrypter() (Encrypter, error)
```
NewEncrypter creates a new AESSymmetricEncrypter
#### type Curve25519Encryption
```go
type Curve25519Encryption struct {
}
```
#### func (*Curve25519Encryption) Encrypt
```go
func (curve25519 *Curve25519Encryption) Encrypt(data []byte) (enc []byte, err error)
```
#### func (*Curve25519Encryption) EncryptPadding
```go
func (curve25519 *Curve25519Encryption) EncryptPadding(data []byte, zeroPadding bool) (encrypted []byte, err error)
```
#### type Curve25519PrivateKey
```go
type Curve25519PrivateKey curve25519.PrivateKey
```
#### type Curve25519PublicKey
```go
type Curve25519PublicKey []byte
```
#### func (Curve25519PublicKey) Len
```go
func (k Curve25519PublicKey) Len() int
```
#### func (Curve25519PublicKey) NewEncrypter
```go
func (elg Curve25519PublicKey) NewEncrypter() (enc Encrypter, err error)
```
#### func (Curve25519PublicKey) NewVerifier
```go
func (k Curve25519PublicKey) NewVerifier() (v Verifier, err error)
```
#### type Curve25519Signer
```go
type Curve25519Signer struct {
}
```
#### func (*Curve25519Signer) Sign
```go
func (s *Curve25519Signer) Sign(data []byte) (sig []byte, err error)
```
#### func (*Curve25519Signer) SignHash
```go
func (s *Curve25519Signer) SignHash(h []byte) (sig []byte, err error)
```
#### type Curve25519Verifier
```go
type Curve25519Verifier struct {
}
```
#### func (*Curve25519Verifier) Verify
```go
func (v *Curve25519Verifier) Verify(data, sig []byte) (err error)
```
#### func (*Curve25519Verifier) VerifyHash
```go
func (v *Curve25519Verifier) VerifyHash(h, sig []byte) (err error)
```
#### type DSAPrivateKey
```go
type DSAPrivateKey [20]byte
```
#### func (DSAPrivateKey) Generate
```go
func (k DSAPrivateKey) Generate() (s DSAPrivateKey, err error)
```
#### func (DSAPrivateKey) Len
```go
func (k DSAPrivateKey) Len() int
```
#### func (DSAPrivateKey) NewSigner
```go
func (k DSAPrivateKey) NewSigner() (s Signer, err error)
```
create a new dsa signer
#### func (DSAPrivateKey) Public
```go
func (k DSAPrivateKey) Public() (pk DSAPublicKey, err error)
```
#### type DSAPublicKey
```go
type DSAPublicKey [128]byte
```
#### func (DSAPublicKey) Len
```go
func (k DSAPublicKey) Len() int
```
#### func (DSAPublicKey) NewVerifier
```go
func (k DSAPublicKey) NewVerifier() (v Verifier, err error)
```
create a new dsa verifier
#### type DSASigner
```go
type DSASigner struct {
}
```
#### func (*DSASigner) Sign
```go
func (ds *DSASigner) Sign(data []byte) (sig []byte, err error)
```
#### func (*DSASigner) SignHash
```go
func (ds *DSASigner) SignHash(h []byte) (sig []byte, err error)
```
#### type DSAVerifier
```go
type DSAVerifier struct {
}
```
#### func (*DSAVerifier) Verify
```go
func (v *DSAVerifier) Verify(data, sig []byte) (err error)
```
verify data with a dsa public key
#### func (*DSAVerifier) VerifyHash
```go
func (v *DSAVerifier) VerifyHash(h, sig []byte) (err error)
```
verify hash of data with a dsa public key
#### type Decrypter
```go
type Decrypter interface {
// decrypt a block of data
// return decrypted block or nil and error if error happens
Decrypt(data []byte) ([]byte, error)
}
```
decrypts data
#### type ECDSAVerifier
```go
type ECDSAVerifier struct {
}
```
#### func (*ECDSAVerifier) Verify
```go
func (v *ECDSAVerifier) Verify(data, sig []byte) (err error)
```
verify a block of data by hashing it and comparing the hash against the
signature
#### func (*ECDSAVerifier) VerifyHash
```go
func (v *ECDSAVerifier) VerifyHash(h, sig []byte) (err error)
```
verify a signature given the hash
#### type ECP256PrivateKey
```go
type ECP256PrivateKey [32]byte
```
#### type ECP256PublicKey
```go
type ECP256PublicKey [64]byte
```
#### func (ECP256PublicKey) Len
```go
func (k ECP256PublicKey) Len() int
```
#### func (ECP256PublicKey) NewVerifier
```go
func (k ECP256PublicKey) NewVerifier() (Verifier, error)
```
#### type ECP384PrivateKey
```go
type ECP384PrivateKey [48]byte
```
#### type ECP384PublicKey
```go
type ECP384PublicKey [96]byte
```
#### func (ECP384PublicKey) Len
```go
func (k ECP384PublicKey) Len() int
```
#### func (ECP384PublicKey) NewVerifier
```go
func (k ECP384PublicKey) NewVerifier() (Verifier, error)
```
#### type ECP521PrivateKey
```go
type ECP521PrivateKey [66]byte
```
#### type ECP521PublicKey
```go
type ECP521PublicKey [132]byte
```
#### func (ECP521PublicKey) Len
```go
func (k ECP521PublicKey) Len() int
```
#### func (ECP521PublicKey) NewVerifier
```go
func (k ECP521PublicKey) NewVerifier() (Verifier, error)
```
#### type Ed25519Encryption
```go
type Ed25519Encryption struct {
}
```
#### func (*Ed25519Encryption) Encrypt
```go
func (ed25519 *Ed25519Encryption) Encrypt(data []byte) (enc []byte, err error)
```
#### func (*Ed25519Encryption) EncryptPadding
```go
func (ed25519 *Ed25519Encryption) EncryptPadding(data []byte, zeroPadding bool) (encrypted []byte, err error)
```
#### type Ed25519PrivateKey
```go
type Ed25519PrivateKey ed25519.PrivateKey
```
#### type Ed25519PublicKey
```go
type Ed25519PublicKey []byte
```
#### func (Ed25519PublicKey) Len
```go
func (k Ed25519PublicKey) Len() int
```
#### func (Ed25519PublicKey) NewEncrypter
```go
func (elg Ed25519PublicKey) NewEncrypter() (enc Encrypter, err error)
```
#### func (Ed25519PublicKey) NewVerifier
```go
func (k Ed25519PublicKey) NewVerifier() (v Verifier, err error)
```
#### type Ed25519Signer
```go
type Ed25519Signer struct {
}
```
#### func (*Ed25519Signer) Sign
```go
func (s *Ed25519Signer) Sign(data []byte) (sig []byte, err error)
```
#### func (*Ed25519Signer) SignHash
```go
func (s *Ed25519Signer) SignHash(h []byte) (sig []byte, err error)
```
#### type Ed25519Verifier
```go
type Ed25519Verifier struct {
}
```
#### func (*Ed25519Verifier) Verify
```go
func (v *Ed25519Verifier) Verify(data, sig []byte) (err error)
```
#### func (*Ed25519Verifier) VerifyHash
```go
func (v *Ed25519Verifier) VerifyHash(h, sig []byte) (err error)
```
#### type ElgPrivateKey
```go
type ElgPrivateKey [256]byte
```
#### func (ElgPrivateKey) Len
```go
func (elg ElgPrivateKey) Len() int
```
#### func (ElgPrivateKey) NewDecrypter
```go
func (elg ElgPrivateKey) NewDecrypter() (dec Decrypter, err error)
```
#### type ElgPublicKey
```go
type ElgPublicKey [256]byte
```
#### func (ElgPublicKey) Len
```go
func (elg ElgPublicKey) Len() int
```
#### func (ElgPublicKey) NewEncrypter
```go
func (elg ElgPublicKey) NewEncrypter() (enc Encrypter, err error)
```
#### type ElgamalEncryption
```go
type ElgamalEncryption struct {
}
```
#### func (*ElgamalEncryption) Encrypt
```go
func (elg *ElgamalEncryption) Encrypt(data []byte) (enc []byte, err error)
```
#### func (*ElgamalEncryption) EncryptPadding
```go
func (elg *ElgamalEncryption) EncryptPadding(data []byte, zeroPadding bool) (encrypted []byte, err error)
```
#### type Encrypter
```go
type Encrypter interface {
// encrypt a block of data
// return encrypted block or nil and error if an error happened
Encrypt(data []byte) (enc []byte, err error)
}
```
encrypts data
#### type HMACDigest
```go
type HMACDigest [16]byte
```
#### func I2PHMAC
```go
func I2PHMAC(data []byte, k HMACKey) (d HMACDigest)
```
do i2p hmac
#### type HMACKey
```go
type HMACKey [32]byte
```
#### type PrivateEncryptionKey
```go
type PrivateEncryptionKey interface {
// create a new decryption object for this private key to decrypt data encrypted to our public key
// returns decrypter or nil and error if the private key is in a bad format
NewDecrypter() (Decrypter, error)
}
```
#### type PublicEncryptionKey
```go
type PublicEncryptionKey interface {
// create a new encrypter to encrypt data to this public key
NewEncrypter() (Encrypter, error)
// length of this public key in bytes
Len() int
}
```
#### type PublicKey
```go
type PublicKey interface {
Len() int
NewEncrypter() (Encrypter, error)
}
```
#### type RSA2048PrivateKey
```go
type RSA2048PrivateKey [512]byte
```
#### type RSA2048PublicKey
```go
type RSA2048PublicKey [256]byte
```
#### type RSA3072PrivateKey
```go
type RSA3072PrivateKey [786]byte
```
#### type RSA3072PublicKey
```go
type RSA3072PublicKey [384]byte
```
#### type RSA4096PrivateKey
```go
type RSA4096PrivateKey [1024]byte
```
#### type RSA4096PublicKey
```go
type RSA4096PublicKey [512]byte
```
#### type Signer
```go
type Signer interface {
// sign data with our private key by calling SignHash after hashing the data we are given
// return signature or nil signature and error if an error happened
Sign(data []byte) (sig []byte, err error)
// sign hash of data with our private key
// return signature or nil signature and error if an error happened
SignHash(h []byte) (sig []byte, err error)
}
```
type for signing data
#### type SigningPrivateKey
```go
type SigningPrivateKey interface {
// create a new signer to sign data
// return signer or nil and error if key format is invalid
NewSigner() (Signer, error)
// length of this private key
Len() int
// get public key or return nil and error if invalid key data in private key
Public() (SigningPublicKey, error)
// generate a new private key, put it into itself
// returns itself or nil and error if an error occurs
Generate() (SigningPrivateKey, error)
}
```
key for signing data
#### type SigningPublicKey
```go
type SigningPublicKey interface {
// create new Verifier to verify the validity of signatures
// return verifier or nil and error if key format is invalid
NewVerifier() (Verifier, error)
// get the size of this public key
Len() int
}
```
key for verifying data
#### type Tunnel
```go
type Tunnel struct {
}
```
#### func NewTunnelCrypto
```go
func NewTunnelCrypto(layerKey, ivKey TunnelKey) (t *Tunnel, err error)
```
#### func (*Tunnel) Decrypt
```go
func (t *Tunnel) Decrypt(td *TunnelData)
```
#### func (*Tunnel) Encrypt
```go
func (t *Tunnel) Encrypt(td *TunnelData)
```
encrypt tunnel data in place
#### type TunnelData
```go
type TunnelData [1028]byte
```
#### type TunnelIV
```go
type TunnelIV []byte
```
The initialization vector for a tunnel message
#### type TunnelKey
```go
type TunnelKey [32]byte
```
A symetric key for encrypting tunnel messages
#### type Verifier
```go
type Verifier interface {
// verify hashed data with this signing key
// return nil on valid signature otherwise error
VerifyHash(h, sig []byte) error
// verify an unhashed piece of data by hashing it and calling VerifyHash
Verify(data, sig []byte) error
}
```
type for verifying signatures

View File

@@ -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
}

View File

@@ -2,7 +2,6 @@ package crypto
import (
"crypto/rand"
log "github.com/sirupsen/logrus"
"io"
"testing"
)

View File

@@ -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,39 +59,64 @@ 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
}
type ECP256PublicKey [64]byte
type ECP256PrivateKey [32]byte
type (
ECP256PublicKey [64]byte
ECP256PrivateKey [32]byte
)
func (k ECP256PublicKey) Len() int {
return len(k)
}
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 ECP384PublicKey [96]byte
type ECP384PrivateKey [48]byte
type (
ECP384PublicKey [96]byte
ECP384PrivateKey [48]byte
)
func (k ECP384PublicKey) Len() int {
return len(k)
}
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 ECP521PublicKey [132]byte
type ECP521PrivateKey [66]byte
type (
ECP521PublicKey [132]byte
ECP521PrivateKey [66]byte
)
func (k ECP521PublicKey) Len() int {
return len(k)
}
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[:])
}

View File

@@ -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
}

View File

@@ -8,6 +8,8 @@ import (
"io"
"math/big"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/openpgp/elgamal"
)
@@ -30,14 +32,19 @@ var elgp = new(big.Int).SetBytes([]byte{
0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
})
var one = big.NewInt(1)
var elgg = big.NewInt(2)
var (
one = big.NewInt(1)
elgg = big.NewInt(2)
)
var ElgDecryptFail = errors.New("failed to decrypt elgamal encrypted data")
var ElgEncryptTooBig = errors.New("failed to encrypt data, too big for elgamal")
var (
ElgDecryptFail = errors.New("failed to decrypt elgamal encrypted data")
ElgEncryptTooBig = errors.New("failed to encrypt data, too big for elgamal")
)
// 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)
@@ -47,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
}
@@ -56,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
@@ -83,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)
@@ -103,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
@@ -130,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)
@@ -158,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 {
@@ -180,20 +221,31 @@ 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
}
type ElgPublicKey [256]byte
type ElgPrivateKey [256]byte
type (
ElgPublicKey [256]byte
ElgPrivateKey [256]byte
)
func (elg ElgPublicKey) Len() int {
return len(elg)
}
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
}
@@ -202,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
}

View File

@@ -3,10 +3,10 @@ package crypto
import (
"bytes"
"crypto/rand"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/openpgp/elgamal"
"io"
"testing"
"golang.org/x/crypto/openpgp/elgamal"
)
func BenchmarkElgGenerate(b *testing.B) {
@@ -46,7 +46,6 @@ func BenchmarkElgDecrypt(b *testing.B) {
}
}
log.Infof("%d fails %d rounds", fails, b.N)
}
func BenchmarkElgEncrypt(b *testing.B) {

View File

@@ -8,7 +8,6 @@ type Encrypter interface {
}
type PublicEncryptionKey interface {
// create a new encrypter to encrypt data to this public key
NewEncrypter() (Encrypter, error)

View File

@@ -4,11 +4,15 @@ import (
"crypto/md5"
)
const IPAD = byte(0x36)
const OPAD = byte(0x5C)
const (
IPAD = byte(0x36)
OPAD = byte(0x5C)
)
type HMACKey [32]byte
type HMACDigest [16]byte
type (
HMACKey [32]byte
HMACDigest [16]byte
)
func (hk HMACKey) xor(p byte) (i []byte) {
i = make([]byte, 64)
@@ -25,7 +29,6 @@ func (hk HMACKey) xor(p byte) (i []byte) {
// do i2p hmac
func I2PHMAC(data []byte, k HMACKey) (d HMACDigest) {
buff := make([]byte, 64+len(data))
ip := k.xor(IPAD)
copy(buff, ip)

View File

@@ -1,10 +1,16 @@
package crypto
type RSA2048PublicKey [256]byte
type RSA2048PrivateKey [512]byte
type (
RSA2048PublicKey [256]byte
RSA2048PrivateKey [512]byte
)
type RSA3072PublicKey [384]byte
type RSA3072PrivateKey [786]byte
type (
RSA3072PublicKey [384]byte
RSA3072PrivateKey [786]byte
)
type RSA4096PublicKey [512]byte
type RSA4096PrivateKey [1024]byte
type (
RSA4096PublicKey [512]byte
RSA4096PrivateKey [1024]byte
)

View File

@@ -4,9 +4,11 @@ import (
"errors"
)
var ErrBadSignatureSize = errors.New("bad signature size")
var ErrInvalidKeyFormat = errors.New("invalid key format")
var ErrInvalidSignature = errors.New("invalid signature")
var (
ErrBadSignatureSize = errors.New("bad signature size")
ErrInvalidKeyFormat = errors.New("invalid key format")
ErrInvalidSignature = errors.New("invalid signature")
)
// type for verifying signatures
type Verifier interface {

View File

@@ -19,7 +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 {
@@ -28,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")
}

View File

@@ -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
@@ -149,8 +153,10 @@ padding :: Data
total length: 222
*/
type BuildRequestRecordElGamalAES [528]byte
type BuildRequestRecordElGamal [528]byte
type (
BuildRequestRecordElGamalAES [528]byte
BuildRequestRecordElGamal [528]byte
)
type BuildRequestRecord struct {
ReceiveTunnel tunnel.TunnelID
@@ -170,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
}
@@ -256,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")
@@ -271,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
@@ -286,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")
@@ -301,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
@@ -315,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
@@ -329,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
@@ -343,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
@@ -357,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
@@ -370,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")
@@ -385,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
@@ -398,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
@@ -412,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

View File

@@ -14,7 +14,6 @@ func TestReadBuildRequestRecordReceiveTunnelTooLittleData(t *testing.T) {
receive_tunnel, err := readBuildRequestRecordReceiveTunnel([]byte{0x01})
assert.Equal(tunnel.TunnelID(0), receive_tunnel)
assert.Equal(ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA, err)
}
func TestReadBuildRequestRecordReceiveTunnelValidData(t *testing.T) {

View File

@@ -38,8 +38,10 @@ byte 527 :: reply
total length: 528
*/
type BuildResponseRecordELGamalAES [528]byte
type BuildResponseRecordELGamal [528]byte
type (
BuildResponseRecordELGamalAES [528]byte
BuildResponseRecordELGamal [528]byte
)
type BuildResponseRecord struct {
Hash common.Hash

343
lib/i2np/doc.md Normal file
View File

@@ -0,0 +1,343 @@
# i2np
--
import "github.com/go-i2p/go-i2p/lib/i2np"
## Usage
```go
const (
I2NP_MESSAGE_TYPE_DATABASE_STORE = 1
I2NP_MESSAGE_TYPE_DATABASE_LOOKUP = 2
I2NP_MESSAGE_TYPE_DATABASE_SEARCH_REPLY = 3
I2NP_MESSAGE_TYPE_DELIVERY_STATUS = 10
I2NP_MESSAGE_TYPE_GARLIC = 11
I2NP_MESSAGE_TYPE_TUNNEL_DATA = 18
I2NP_MESSAGE_TYPE_TUNNEL_GATEWAY = 19
I2NP_MESSAGE_TYPE_DATA = 20
I2NP_MESSAGE_TYPE_TUNNEL_BUILD = 21
I2NP_MESSAGE_TYPE_TUNNEL_BUILD_REPLY = 22
I2NP_MESSAGE_TYPE_VARIABLE_TUNNEL_BUILD = 23
I2NP_MESSAGE_TYPE_VARIABLE_TUNNEL_BUILD_REPLY = 24
)
```
```go
var ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA = errors.New("not enough i2np build request record data")
```
```go
var ERR_I2NP_NOT_ENOUGH_DATA = errors.New("not enough i2np header data")
```
#### func ReadI2NPNTCPData
```go
func ReadI2NPNTCPData(data []byte, size int) ([]byte, error)
```
#### func ReadI2NPNTCPMessageChecksum
```go
func ReadI2NPNTCPMessageChecksum(data []byte) (int, error)
```
#### func ReadI2NPNTCPMessageExpiration
```go
func ReadI2NPNTCPMessageExpiration(data []byte) (datalib.Date, error)
```
#### func ReadI2NPNTCPMessageID
```go
func ReadI2NPNTCPMessageID(data []byte) (int, error)
```
#### func ReadI2NPNTCPMessageSize
```go
func ReadI2NPNTCPMessageSize(data []byte) (int, error)
```
#### func ReadI2NPSSUMessageExpiration
```go
func ReadI2NPSSUMessageExpiration(data []byte) (datalib.Date, error)
```
#### func ReadI2NPType
```go
func ReadI2NPType(data []byte) (int, error)
```
#### type BuildRequestRecord
```go
type BuildRequestRecord struct {
ReceiveTunnel tunnel.TunnelID
OurIdent common.Hash
NextTunnel tunnel.TunnelID
NextIdent common.Hash
LayerKey session_key.SessionKey
IVKey session_key.SessionKey
ReplyKey session_key.SessionKey
ReplyIV [16]byte
Flag int
RequestTime time.Time
SendMessageID int
Padding [29]byte
}
```
#### func ReadBuildRequestRecord
```go
func ReadBuildRequestRecord(data []byte) (BuildRequestRecord, error)
```
#### type BuildRequestRecordElGamal
```go
type BuildRequestRecordElGamal [528]byte
```
#### type BuildRequestRecordElGamalAES
```go
type BuildRequestRecordElGamalAES [528]byte
```
#### type BuildResponseRecord
```go
type BuildResponseRecord struct {
Hash common.Hash
Padding [495]byte
Reply byte
}
```
#### type BuildResponseRecordELGamal
```go
type BuildResponseRecordELGamal [528]byte
```
#### type BuildResponseRecordELGamalAES
```go
type BuildResponseRecordELGamalAES [528]byte
```
#### type Data
```go
type Data struct {
Length int
Data []byte
}
```
#### type DatabaseLookup
```go
type DatabaseLookup struct {
Key common.Hash
From common.Hash
Flags byte
ReplyTunnelID [4]byte
Size int
ExcludedPeers []common.Hash
ReplyKey session_key.SessionKey
ReplyTags []session_tag.SessionTag
}
```
#### type DatabaseSearchReply
```go
type DatabaseSearchReply struct {
Key common.Hash
Count int
PeerHashes []common.Hash
From common.Hash
}
```
#### type DatabaseStore
```go
type DatabaseStore struct {
Key common.Hash
Type byte
ReplyToken [4]byte
ReplyTunnelID [4]byte
ReplyGateway common.Hash
Data []byte
}
```
#### type DeliveryStatus
```go
type DeliveryStatus struct {
MessageID int
Timestamp time.Time
}
```
#### type Garlic
```go
type Garlic struct {
Count int
Cloves []GarlicClove
Certificate certificate.Certificate
MessageID int
Expiration time.Time
}
```
#### type GarlicClove
```go
type GarlicClove struct {
DeliveryInstructions GarlicCloveDeliveryInstructions
I2NPMessage I2NPMessage
CloveID int
Expiration time.Time
Certificate certificate.Certificate
}
```
#### type GarlicCloveDeliveryInstructions
```go
type GarlicCloveDeliveryInstructions struct {
Flag byte
SessionKey session_key.SessionKey
Hash common.Hash
TunnelID tunnel.TunnelID
Delay int
}
```
#### type GarlicElGamal
```go
type GarlicElGamal []byte
```
#### type I2NPMessage
```go
type I2NPMessage []byte
```
#### type I2NPNTCPHeader
```go
type I2NPNTCPHeader struct {
Type int
MessageID int
Expiration time.Time
Size int
Checksum int
Data []byte
}
```
#### func ReadI2NPNTCPHeader
```go
func ReadI2NPNTCPHeader(data []byte) (I2NPNTCPHeader, error)
```
Read an entire I2NP message and return the parsed header with embedded encrypted
data
#### type I2NPSSUHeader
```go
type I2NPSSUHeader struct {
Type int
Expiration time.Time
}
```
#### func ReadI2NPSSUHeader
```go
func ReadI2NPSSUHeader(data []byte) (I2NPSSUHeader, error)
```
#### type TunnelBuild
```go
type TunnelBuild [8]BuildRequestRecord
```
#### type TunnelBuildReply
```go
type TunnelBuildReply [8]BuildResponseRecord
```
#### type TunnelData
```go
type TunnelData [1028]byte
```
#### type TunnelGatway
```go
type TunnelGatway struct {
TunnelID tunnel.TunnelID
Length int
Data []byte
}
```
#### type VariableTunnelBuild
```go
type VariableTunnelBuild struct {
Count int
BuildRequestRecords []BuildRequestRecord
}
```
#### type VariableTunnelBuildReply
```go
type VariableTunnelBuildReply struct {
Count int
BuildResponseRecords []BuildResponseRecord
}
```

View File

@@ -0,0 +1,12 @@
# exportable
--
import "github.com/go-i2p/go-i2p/lib/i2np/fuzz/header"
## Usage
#### func Fuzz
```go
func Fuzz(data []byte) int
```

View File

@@ -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
}

Some files were not shown because too many files have changed in this diff Show More