mirror of
https://github.com/go-i2p/go-i2p.git
synced 2025-07-13 11:54:46 -04:00
Compare commits
191 Commits
0.0.1
...
routerinfo
Author | SHA1 | Date | |
---|---|---|---|
627e131a58 | |||
f729bda62d | |||
4ad0f97bfe | |||
20032e0f55 | |||
700391788f | |||
e296441f29 | |||
62086c7d04 | |||
ddba94d6ae | |||
767b91df49 | |||
1292098cf0 | |||
24bc4c3c17 | |||
81eb270351 | |||
b6f197cf92 | |||
c10d98a3b2 | |||
6d16ca5f87 | |||
003d6c9ab8 | |||
015c4b23e2 | |||
e29c3c7abb | |||
6f6291a9f6 | |||
767864d457 | |||
0a98236d85 | |||
c1fa63f6ec | |||
a75c275b4c | |||
d40b3e0cd3 | |||
2ee2d77d7c | |||
df45c19272 | |||
f6894e9064 | |||
b36ef65a10 | |||
271cf56ded | |||
a29fa0bc03 | |||
63c48dd3b7 | |||
8bec47efd2 | |||
69a50e2035 | |||
8319444890 | |||
b378661e0e | |||
f4086e5f68 | |||
877fc707c4 | |||
98d05e27c8 | |||
8c2b952616 | |||
4020db8a19 | |||
67a02f5d69 | |||
ca1280231c | |||
02b309df43 | |||
a5b3c3f194 | |||
0aa7a5554b | |||
266a1b71d6 | |||
d32f2e78ab | |||
9e806bc32e | |||
c52112a36f | |||
db0fd9f7e9 | |||
3ab258cde6 | |||
20b9bbd8e4 | |||
1fa520613c | |||
fb99b98a7e | |||
d6b8cd9d4d | |||
92e4656774 | |||
5f2bfb8d9d | |||
9494c226a6 | |||
344edc6d41 | |||
9eea99b489 | |||
c984f94b90 | |||
a17f0208dd | |||
487815f8f1 | |||
24e0baa879 | |||
a5d2f0de8c | |||
423f616d53 | |||
c65048f3c4 | |||
39b683dac8 | |||
46883f6457 | |||
4be55062fc | |||
12a3fd4623 | |||
80e539930e | |||
e58d326d89 | |||
e6f84c16f6 | |||
971a18de8d | |||
833836ae67 | |||
3f191db37a | |||
6865bae386 | |||
f0d9f89ed9 | |||
c149eef1de | |||
748dc8a66f | |||
677aac500e | |||
4e06d3d5ed | |||
5eaa9cf588 | |||
4dbf537e94 | |||
882c018c0c | |||
5432502852 | |||
0ea5743365 | |||
a9dc482bda | |||
c31d20fec0 | |||
647546a374 | |||
e468520906 | |||
ade80e577c | |||
f45d301868 | |||
0256908395 | |||
3c5aa206d1 | |||
a4517cafd7 | |||
f4f39ca53c | |||
220159476a | |||
792cd49208 | |||
68051630c0 | |||
a3340eb40a | |||
465a7787a9 | |||
af3bc44dba | |||
f850f482cf | |||
3f23376d22 | |||
aa98589f1c | |||
c31e990995 | |||
8e97eb5f77 | |||
be35267079 | |||
013d35b447 | |||
e8c9dc17a3 | |||
a1d574446b | |||
8680acc595 | |||
84e3c5accc | |||
e772fb5ceb | |||
a533cd7ce4 | |||
df37d49444 | |||
4b2600a065 | |||
1c4f937002 | |||
5c2b408f65 | |||
beb533a09b | |||
f022522ad5 | |||
2191c40ac6 | |||
3bca467f28 | |||
a2fd65ee32 | |||
b894e8fb17 | |||
93a71c7398 | |||
b6544ad194 | |||
a72b61a886 | |||
dda4f90b6f | |||
1d1d8126c2 | |||
73db39ae50 | |||
53e902f491 | |||
2f2cd2249c | |||
4496c11394 | |||
69449a20b5 | |||
a7689e801a | |||
278bdee277 | |||
684e89c957 | |||
50fa9fc374 | |||
491b25022e | |||
677a6b354b | |||
9469fd83aa | |||
8173ae49e6 | |||
2f109d5b4d | |||
d7378d7b08 | |||
3a51a1229e | |||
2b18b2941d | |||
1eb29ec4ab | |||
d900d7faf8 | |||
03c9d60ab9 | |||
de2caf499e | |||
284dd7287e | |||
9f4154ff45 | |||
08a0d92742 | |||
524526d946 | |||
09c7d32797 | |||
16961abc96 | |||
8fa355f067 | |||
0c7a3f0f22 | |||
3d535f67a1 | |||
bba9350506 | |||
cbc0de4e7e | |||
310ef07d3c | |||
14fc6fc3a8 | |||
a3ce9d36c6 | |||
58a43cdfaf | |||
15a5ca5daf | |||
08a41686b6 | |||
8318fd8f57 | |||
9c0552e236 | |||
20b018a708 | |||
6c62faa49b | |||
a7e31b7833 | |||
c09161c824 | |||
aca62174e6 | |||
bd27f00959 | |||
05c4d3d973 | |||
40d0ea5ff5 | |||
58e8f78c56 | |||
65febb5dcf | |||
116e22f8da | |||
0419665d7b | |||
dab108c270 | |||
0fcded4c51 | |||
7d16b0b257 | |||
a689f26d73 | |||
fdc34b382e | |||
a4ed06e530 | |||
6b5ea57cbd |
20
.github/workflows/auto-assign.yml
vendored
Normal file
20
.github/workflows/auto-assign.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
name: Auto Assign
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
pull_request:
|
||||
types: [opened]
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: 'Auto-assign issue'
|
||||
uses: pozil/auto-assign-issue@v1
|
||||
with:
|
||||
repo-token:${{ secrets.GITHUB_TOKEN }}
|
||||
assignees: eyedeekay
|
||||
numOfAssignee: 1
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,3 +7,5 @@
|
||||
go-i2p
|
||||
*.exe
|
||||
.idea/
|
||||
router.info
|
||||
log
|
||||
|
47
Makefile
47
Makefile
@ -2,6 +2,8 @@ RELEASE_TAG=0.0.1
|
||||
RELEASE_VERSION=${RELEASE_TAG}
|
||||
RELEASE_DESCRIPTION=`cat PASTA.md`
|
||||
REPO := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
CGO_ENABLED=0
|
||||
export DEBUG_I2P=debug
|
||||
|
||||
ifdef GOROOT
|
||||
GO = $(GOROOT)/bin/go
|
||||
@ -15,19 +17,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 +42,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
|
18
PASTA.md
18
PASTA.md
@ -1,18 +0,0 @@
|
||||
At long last... something useful
|
||||
================================
|
||||
|
||||
It's been 2 years of me mostly not having time to work on go-i2p itself since my last update.
|
||||
However, after much waiting, this library is actually **useful** for something.
|
||||
It is now being used in the `reseed-tools` application to examine RouterInfos prior to including them in reseed bundles.
|
||||
Routers that self-report as unreachable or congested will be excluded from future reseed bundles.
|
||||
Additionally, routers that self-report an old version will be excluded from reseed bundles.
|
||||
This should help new users build better connections faster with the existing, working router implementations.
|
||||
|
||||
This is not a working release of a go-i2p router
|
||||
------------------------------------------------
|
||||
|
||||
It is a numbered version of the go-i2p library, which is pre-release, expressly for use in the `reseed-tools` application.
|
||||
The common library works, and so do some of the cryptographic primitives, however the API is unstable and the software itself is certain to have serious bugs outside of a few well-tested areas.
|
||||
If you're using it for something other than parsing and analyzing RouterInfos and LeaseSets, you'll probably encounter bugs.
|
||||
Please report them to the https://github.com/go-i2p/go-i2p
|
||||
Use any part of it at your own risk.
|
37
README.md
37
README.md
@ -41,7 +41,7 @@ please keep up with these changes, as they will not be backward compatible and r
|
||||
- [ ] Elligator2
|
||||
- [ ] HKDF
|
||||
- [ ] HMAC
|
||||
- [ ] Noise subsystem
|
||||
- [X] Noise subsystem
|
||||
- End-to-End Crypto
|
||||
- [ ] Garlic messages
|
||||
- [ ] ElGamal/AES+SessionTag
|
||||
@ -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,37 @@ 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 DEBUG_I2P is set to an unrecognized variable, it will fall back to "debug".
|
||||
|
||||
## Fast-Fail mode ##
|
||||
|
||||
Fast-Fail mode can be activated by setting `WARNFAIL_I2P` to any non-empty value. When set, every warning or error is Fatal.
|
||||
It is unsafe for production use, and intended only for debugging and testing purposes.
|
||||
|
||||
```shell
|
||||
export WARNFAIL_I2P=true
|
||||
```
|
||||
|
||||
If `WARNFAIL_I2P` is set and `DEBUG_I2P` is unset, `DEBUG_I2P` will be set to `debug`.
|
||||
|
||||
## Contributing
|
||||
|
||||
See CONTRIBUTING.md for more information.
|
||||
|
41
ROADMAP.md
Normal file
41
ROADMAP.md
Normal file
@ -0,0 +1,41 @@
|
||||
# go-i2p Implementation Roadmap
|
||||
|
||||
## Transport Layer (NTCP2)
|
||||
- Build on existing lib/transport/noise implementation
|
||||
- Core NTCP2 components:
|
||||
* Session handshake using noise protocol
|
||||
* Connection management
|
||||
* I2NP message transport
|
||||
|
||||
## Reseed System
|
||||
- SU3 file format implementation:
|
||||
* Format parsing and validation(Much of this work is done in reseed-tools, may need to be moved here)
|
||||
* Signature verification system(Much of this work is done in reseed-tools, may need to be moved here)
|
||||
- Local reseed functionality:
|
||||
* File-based reseed operations
|
||||
- Self-signed/Package-pinned X.509 certificate handling for reseed validation
|
||||
|
||||
## NetDb and Database Store
|
||||
- Database Store message handling:
|
||||
* Message structure implementation
|
||||
* Message handling implementation
|
||||
- NetDb core implementation:
|
||||
* RouterInfo management
|
||||
* LeaseSet management
|
||||
* Lookup system
|
||||
* Storage interface
|
||||
* Peer selection logic?(Maybe do something very basic for now like i2pd used to do, and then improve it later, the important part will be interface design at first)
|
||||
|
||||
## Tunnel Implementation
|
||||
- Tunnel cryptography:
|
||||
* Key generation and management
|
||||
* Layered encryption scheme
|
||||
- Message processing:
|
||||
* Build request/response handling
|
||||
* Gateway implementation
|
||||
* Message forwarding logic
|
||||
|
||||
Notes:
|
||||
- Excluding legacy protocols (SSU1, NTCP1, elgamal, DSA)
|
||||
- Leveraging existing noise protocol implementation
|
||||
- SSU2 is not on this roadmap but is fair game for implementation as soon as NTCP2 is done. We're focused on NTCP2 to get this thing sending I2NP messages.
|
17
doc/tests/aes.mk
Normal file
17
doc/tests/aes.mk
Normal file
@ -0,0 +1,17 @@
|
||||
test-crypto-aes-all: test-crypto-aes-core test-crypto-aes-validation test-crypto-aes-padding
|
||||
|
||||
test-crypto-aes-core:
|
||||
$(GO) test -v ./lib/crypto -run TestAESEncryptDecrypt
|
||||
|
||||
test-crypto-aes-validation:
|
||||
$(GO) test -v ./lib/crypto -run TestAESEncryptInvalidKey
|
||||
$(GO) test -v ./lib/crypto -run TestAESDecryptInvalidInput
|
||||
|
||||
test-crypto-aes-padding:
|
||||
$(GO) test -v ./lib/crypto -run TestPKCS7PadUnpad
|
||||
$(GO) test -v ./lib/crypto -run TestPKCS7UnpadInvalidInput
|
||||
|
||||
.PHONY: test-crypto-aes-all \
|
||||
test-crypto-aes-core \
|
||||
test-crypto-aes-validation \
|
||||
test-crypto-aes-padding
|
4
doc/tests/base32.mk
Normal file
4
doc/tests/base32.mk
Normal file
@ -0,0 +1,4 @@
|
||||
test-base32-encode-decode-not-mangled:
|
||||
$(GO) test -v ./lib/common/base32 -run TestEncodeDecodeNotMangled
|
||||
|
||||
.PHONY: test-base32-encode-decode-not-mangled
|
4
doc/tests/base64.mk
Normal file
4
doc/tests/base64.mk
Normal file
@ -0,0 +1,4 @@
|
||||
test-base64-encode-decode-not-mangled:
|
||||
$(GO) test -v ./lib/common/base64 -run TestEncodeDecodeNotMangled
|
||||
|
||||
.PHONY: test-base64-encode-decode-not-mangled
|
24
doc/tests/build_request_record.mk
Normal file
24
doc/tests/build_request_record.mk
Normal file
@ -0,0 +1,24 @@
|
||||
test-build-request-all: test-build-request-receive test-build-request-ident test-build-request-components
|
||||
|
||||
test-build-request-receive:
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordReceiveTunnel
|
||||
|
||||
test-build-request-ident:
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordOurIdent
|
||||
|
||||
test-build-request-components:
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordNextTunnel
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordNextIdent
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordLayerKey
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordIVKey
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordReplyKey
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordReplyIV
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordFlag
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordRequestTime
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordSendMessageID
|
||||
$(GO) test -v ./lib/i2np -run TestReadBuildRequestRecordPadding
|
||||
|
||||
.PHONY: test-build-request-all \
|
||||
test-build-request-receive \
|
||||
test-build-request-ident \
|
||||
test-build-request-components
|
61
doc/tests/certificate.mk
Normal file
61
doc/tests/certificate.mk
Normal file
@ -0,0 +1,61 @@
|
||||
|
||||
test-cert-all: test-cert-type test-cert-length test-cert-data test-cert-read test-cert-length-correct test-cert-length-too-short test-cert-length-data-short test-cert-data-correct test-cert-data-too-long test-cert-data-too-short test-cert-read-correct test-cert-read-short test-cert-read-remainder test-cert-read-invalid
|
||||
|
||||
test-cert-type:
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateTypeIsFirstByte
|
||||
|
||||
test-cert-length:
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateLength
|
||||
|
||||
test-cert-data:
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateData
|
||||
|
||||
test-cert-read:
|
||||
$(GO) test -v ./lib/common/certificate -run TestReadCertificate
|
||||
|
||||
test-cert-length-correct:
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateLengthCorrect
|
||||
|
||||
test-cert-length-too-short:
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateLengthErrWhenTooShort
|
||||
|
||||
test-cert-length-data-short:
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateLengthErrWhenDataTooShort
|
||||
|
||||
test-cert-data-correct:
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateDataWhenCorrectSize
|
||||
|
||||
test-cert-data-too-long:
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateDataWhenTooLong
|
||||
|
||||
test-cert-data-too-short:
|
||||
$(GO) test -v ./lib/common/certificate -run TestCertificateDataWhenTooShort
|
||||
|
||||
test-cert-read-correct:
|
||||
$(GO) test -v ./lib/common/certificate -run TestReadCertificateWithCorrectData
|
||||
|
||||
test-cert-read-short:
|
||||
$(GO) test -v ./lib/common/certificate -run TestReadCertificateWithDataTooShort
|
||||
|
||||
test-cert-read-remainder:
|
||||
$(GO) test -v ./lib/common/certificate -run TestReadCertificateWithRemainder
|
||||
|
||||
test-cert-read-invalid:
|
||||
$(GO) test -v ./lib/common/certificate -run TestReadCertificateWithInvalidLength
|
||||
|
||||
# Declare all targets as PHONY
|
||||
.PHONY: test-cert-all \
|
||||
test-cert-type \
|
||||
test-cert-length \
|
||||
test-cert-data \
|
||||
test-cert-read \
|
||||
test-cert-length-correct \
|
||||
test-cert-length-too-short \
|
||||
test-cert-length-data-short \
|
||||
test-cert-data-correct \
|
||||
test-cert-data-too-long \
|
||||
test-cert-data-too-short \
|
||||
test-cert-read-correct \
|
||||
test-cert-read-short \
|
||||
test-cert-read-remainder \
|
||||
test-cert-read-invalid
|
2
doc/tests/date.mk
Normal file
2
doc/tests/date.mk
Normal file
@ -0,0 +1,2 @@
|
||||
test-date-time-from-milliseconds:
|
||||
$(GO) test -v ./lib/common/data -run TestTimeFromMilliseconds
|
20
doc/tests/dsa.mk
Normal file
20
doc/tests/dsa.mk
Normal file
@ -0,0 +1,20 @@
|
||||
test-crypto-dsa-all: test-crypto-dsa test-crypto-dsa-benchmarks
|
||||
|
||||
test-crypto-dsa:
|
||||
$(GO) test -v ./lib/crypto -run TestDSA
|
||||
|
||||
test-crypto-dsa-benchmarks:
|
||||
$(GO) test -v ./lib/crypto -bench=DSA -run=^$
|
||||
|
||||
# Individual benchmarks
|
||||
test-crypto-dsa-bench-generate:
|
||||
$(GO) test -v ./lib/crypto -bench=DSAGenerate -run=^$
|
||||
|
||||
test-crypto-dsa-bench-sign-verify:
|
||||
$(GO) test -v ./lib/crypto -bench=DSASignVerify -run=^$
|
||||
|
||||
.PHONY: test-crypto-dsa-all \
|
||||
test-crypto-dsa \
|
||||
test-crypto-dsa-benchmarks \
|
||||
test-crypto-dsa-bench-generate \
|
||||
test-crypto-dsa-bench-sign-verify
|
7
doc/tests/ed25519.mk
Normal file
7
doc/tests/ed25519.mk
Normal file
@ -0,0 +1,7 @@
|
||||
test-crypto-ed25519-all: test-crypto-ed25519
|
||||
|
||||
test-crypto-ed25519:
|
||||
$(GO) test -v ./lib/crypto -run TestEd25519
|
||||
|
||||
.PHONY: test-crypto-ed25519-all \
|
||||
test-crypto-ed25519
|
24
doc/tests/elg.mk
Normal file
24
doc/tests/elg.mk
Normal file
@ -0,0 +1,24 @@
|
||||
test-crypto-elg-all: test-crypto-elg test-crypto-elg-benchmarks
|
||||
|
||||
test-crypto-elg:
|
||||
$(GO) test -v ./lib/crypto -run TestElg
|
||||
|
||||
test-crypto-elg-benchmarks:
|
||||
$(GO) test -v ./lib/crypto -bench=Elg -run=^$
|
||||
|
||||
# Individual benchmarks
|
||||
test-crypto-elg-bench-generate:
|
||||
$(GO) test -v ./lib/crypto -bench=ElgGenerate -run=^$
|
||||
|
||||
test-crypto-elg-bench-encrypt:
|
||||
$(GO) test -v ./lib/crypto -bench=ElgEncrypt -run=^$
|
||||
|
||||
test-crypto-elg-bench-decrypt:
|
||||
$(GO) test -v ./lib/crypto -bench=ElgDecrypt -run=^$
|
||||
|
||||
.PHONY: test-crypto-elg-all \
|
||||
test-crypto-elg \
|
||||
test-crypto-elg-benchmarks \
|
||||
test-crypto-elg-bench-generate \
|
||||
test-crypto-elg-bench-encrypt \
|
||||
test-crypto-elg-bench-decrypt
|
30
doc/tests/header.mk
Normal file
30
doc/tests/header.mk
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
test-i2np-header-all: test-i2np-type test-i2np-message test-i2np-expiration test-i2np-ntcp-components test-i2np-data test-i2np-regression
|
||||
|
||||
test-i2np-type:
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPTypeWith
|
||||
|
||||
test-i2np-message:
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPMessageID
|
||||
|
||||
test-i2np-expiration:
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPMessageExpiration
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPSSUMessageExpiration
|
||||
|
||||
test-i2np-ntcp-components:
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPMessageSize
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPMessageChecksum
|
||||
|
||||
test-i2np-data:
|
||||
$(GO) test -v ./lib/i2np -run TestReadI2NPNTCPData
|
||||
|
||||
test-i2np-regression:
|
||||
$(GO) test -v ./lib/i2np -run TestCrasherRegression123781
|
||||
|
||||
.PHONY: test-i2np-header-all \
|
||||
test-i2np-type \
|
||||
test-i2np-message \
|
||||
test-i2np-expiration \
|
||||
test-i2np-ntcp-components \
|
||||
test-i2np-data \
|
||||
test-i2np-regression
|
7
doc/tests/hmac.mk
Normal file
7
doc/tests/hmac.mk
Normal file
@ -0,0 +1,7 @@
|
||||
test-crypto-hmac-all: test-crypto-hmac
|
||||
|
||||
test-crypto-hmac:
|
||||
$(GO) test -v ./lib/crypto -run Test_I2PHMAC
|
||||
|
||||
.PHONY: test-crypto-hmac-all \
|
||||
test-crypto-hmac
|
15
doc/tests/integer.mk
Normal file
15
doc/tests/integer.mk
Normal file
@ -0,0 +1,15 @@
|
||||
test-integer-all: test-integer-big-endian test-integer-one-byte test-integer-zero
|
||||
|
||||
test-integer-big-endian:
|
||||
$(GO) test -v ./lib/common/integer -run TestIntegerBigEndian
|
||||
|
||||
test-integer-one-byte:
|
||||
$(GO) test -v ./lib/common/integer -run TestWorksWithOneByte
|
||||
|
||||
test-integer-zero:
|
||||
$(GO) test -v ./lib/common/integer -run TestIsZeroWithNoData
|
||||
|
||||
.PHONY: test-integer-all \
|
||||
test-integer-big-endian \
|
||||
test-integer-one-byte \
|
||||
test-integer-zero
|
23
doc/tests/key_certificate.mk
Normal file
23
doc/tests/key_certificate.mk
Normal file
@ -0,0 +1,23 @@
|
||||
test-key-cert-all: test-key-cert-signing test-key-cert-public test-key-cert-construct
|
||||
|
||||
test-key-cert-signing:
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestSingingPublicKeyTypeReturnsCorrectInteger
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestSingingPublicKeyTypeReportsWhenDataTooSmall
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyReportsWhenDataTooSmall
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithDSASHA1
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP256
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP384
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP521
|
||||
|
||||
test-key-cert-public:
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestPublicKeyTypeReturnsCorrectInteger
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestPublicKeyTypeReportsWhenDataTooSmall
|
||||
|
||||
test-key-cert-construct:
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructPublicKeyReportsWhenDataTooSmall
|
||||
$(GO) test -v ./lib/common/key_certificate -run TestConstructPublicKeyReturnsCorrectDataWithElg
|
||||
|
||||
.PHONY: test-key-cert-all \
|
||||
test-key-cert-signing \
|
||||
test-key-cert-public \
|
||||
test-key-cert-construct
|
30
doc/tests/keys_and_cert.mk
Normal file
30
doc/tests/keys_and_cert.mk
Normal file
@ -0,0 +1,30 @@
|
||||
test-keys-cert-all: test-keys-cert-certificate test-keys-cert-public test-keys-cert-signing test-keys-cert-creation
|
||||
|
||||
test-keys-cert-certificate:
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestCertificateWithValidData
|
||||
|
||||
test-keys-cert-public:
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestPublicKeyWithBadData
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestPublicKeyWithBadCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestPublicKeyWithNullCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestPublicKeyWithKeyCertificate
|
||||
|
||||
test-keys-cert-signing:
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithBadData
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithBadCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithNullCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithKeyCertificate
|
||||
|
||||
test-keys-cert-creation:
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithMissingData
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithMissingCertData
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithoutCertificate
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithCertificateAndRemainder
|
||||
$(GO) test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithoutCertificateAndRemainder
|
||||
|
||||
.PHONY: test-keys-cert-all \
|
||||
test-keys-cert-certificate \
|
||||
test-keys-cert-public \
|
||||
test-keys-cert-signing \
|
||||
test-keys-cert-creation
|
22
doc/tests/lease_set.mk
Normal file
22
doc/tests/lease_set.mk
Normal file
@ -0,0 +1,22 @@
|
||||
test-lease-set-all: test-lease-set-basic test-lease-set-leases test-lease-set-expiration
|
||||
|
||||
test-lease-set-basic:
|
||||
$(GO) test -v ./lib/common/lease_set -run TestDestinationIsCorrect
|
||||
$(GO) test -v ./lib/common/lease_set -run TestPublicKeyIsCorrect
|
||||
$(GO) test -v ./lib/common/lease_set -run TestSigningKeyIsCorrect
|
||||
$(GO) test -v ./lib/common/lease_set -run TestSignatureIsCorrect
|
||||
|
||||
test-lease-set-leases:
|
||||
$(GO) test -v ./lib/common/lease_set -run TestLeaseCountCorrect
|
||||
$(GO) test -v ./lib/common/lease_set -run TestLeaseCountCorrectWithMultiple
|
||||
$(GO) test -v ./lib/common/lease_set -run TestLeaseCountErrorWithTooMany
|
||||
$(GO) test -v ./lib/common/lease_set -run TestLeasesHaveCorrectData
|
||||
|
||||
test-lease-set-expiration:
|
||||
$(GO) test -v ./lib/common/lease_set -run TestNewestExpirationIsCorrect
|
||||
$(GO) test -v ./lib/common/lease_set -run TestOldestExpirationIsCorrect
|
||||
|
||||
.PHONY: test-lease-set-all \
|
||||
test-lease-set-basic \
|
||||
test-lease-set-leases \
|
||||
test-lease-set-expiration
|
28
doc/tests/mapping.mk
Normal file
28
doc/tests/mapping.mk
Normal file
@ -0,0 +1,28 @@
|
||||
test-mapping-all: test-mapping-values test-mapping-duplicates test-mapping-conversion test-mapping-utils
|
||||
|
||||
test-mapping-values:
|
||||
$(GO) test -v ./lib/common/data -run TestValuesExclusesPairWithBadData
|
||||
$(GO) test -v ./lib/common/data -run TestValuesWarnsMissingData
|
||||
$(GO) test -v ./lib/common/data -run TestValuesWarnsExtraData
|
||||
$(GO) test -v ./lib/common/data -run TestValuesEnforcesEqualDelimitor
|
||||
$(GO) test -v ./lib/common/data -run TestValuesEnforcedSemicolonDelimitor
|
||||
$(GO) test -v ./lib/common/data -run TestValuesReturnsValues
|
||||
|
||||
test-mapping-duplicates:
|
||||
$(GO) test -v ./lib/common/data -run TestHasDuplicateKeysTrueWhenDuplicates
|
||||
$(GO) test -v ./lib/common/data -run TestHasDuplicateKeysFalseWithoutDuplicates
|
||||
$(GO) test -v ./lib/common/data -run TestReadMappingHasDuplicateKeys
|
||||
|
||||
test-mapping-conversion:
|
||||
$(GO) test -v ./lib/common/data -run TestGoMapToMappingProducesCorrectMapping
|
||||
$(GO) test -v ./lib/common/data -run TestFullGoMapToMappingProducesCorrectMapping
|
||||
|
||||
test-mapping-utils:
|
||||
$(GO) test -v ./lib/common/data -run TestStopValueRead
|
||||
$(GO) test -v ./lib/common/data -run TestBeginsWith
|
||||
|
||||
.PHONY: test-mapping-all \
|
||||
test-mapping-values \
|
||||
test-mapping-duplicates \
|
||||
test-mapping-conversion \
|
||||
test-mapping-utils
|
2
doc/tests/mapping_values.mk
Normal file
2
doc/tests/mapping_values.mk
Normal file
@ -0,0 +1,2 @@
|
||||
test-mapping-values-order:
|
||||
$(GO) test -v ./lib/common/data -run TestMappingOrderSortsValuesThenKeys
|
19
doc/tests/noise.mk
Normal file
19
doc/tests/noise.mk
Normal file
@ -0,0 +1,19 @@
|
||||
test-noise-transport-all: test-noise-packet-encryption test-noise-transport-connection test-noise-packet-obfuscation test-noise-packet-obfuscation-func
|
||||
|
||||
test-noise-packet-encryption:
|
||||
$(GO) test -v ./lib/transport/noise -run TestEncryptDecryptPacketOffline
|
||||
|
||||
test-noise-transport-connection:
|
||||
$(GO) test -v ./lib/transport/noise -run TestTransport
|
||||
|
||||
test-noise-packet-obfuscation:
|
||||
$(GO) test -v ./lib/transport/noise -run TestEncryptDecryptPacketObfsOffline
|
||||
|
||||
test-noise-packet-obfuscation-func:
|
||||
$(GO) test -v ./lib/transport/noise -run TestEncryptDecryptPacketObfsOfflineWithFunc
|
||||
|
||||
.PHONY: test-noise-transport-all \
|
||||
test-noise-packet-encryption \
|
||||
test-noise-transport-connection \
|
||||
test-noise-packet-obfuscation \
|
||||
test-noise-packet-obfuscation-func
|
19
doc/tests/router_address.mk
Normal file
19
doc/tests/router_address.mk
Normal file
@ -0,0 +1,19 @@
|
||||
test-router-address-all: test-router-address-validation test-router-address-functionality test-router-address-fuzz
|
||||
|
||||
test-router-address-validation:
|
||||
$(GO) test -v ./lib/common/router_address -run TestCheckValidReportsEmptySlice
|
||||
$(GO) test -v ./lib/common/router_address -run TestCheckRouterAddressValidReportsDataMissing
|
||||
$(GO) test -v ./lib/common/router_address -run TestCheckRouterAddressValidNoErrWithValidData
|
||||
|
||||
test-router-address-functionality:
|
||||
$(GO) test -v ./lib/common/router_address -run TestRouterAddressCostReturnsFirstByte
|
||||
$(GO) test -v ./lib/common/router_address -run TestRouterAddressExpirationReturnsCorrectData
|
||||
$(GO) test -v ./lib/common/router_address -run TestReadRouterAddressReturnsCorrectRemainderWithoutError
|
||||
|
||||
test-router-address-fuzz:
|
||||
$(GO) test -v ./lib/common/router_address -run TestCorrectsFuzzCrasher1
|
||||
|
||||
.PHONY: test-router-address-all \
|
||||
test-router-address-validation \
|
||||
test-router-address-functionality \
|
||||
test-router-address-fuzz
|
26
doc/tests/router_info.mk
Normal file
26
doc/tests/router_info.mk
Normal file
@ -0,0 +1,26 @@
|
||||
test-router-info-all: test-router-info-published test-router-info-addresses test-router-info-identity test-router-info-misc
|
||||
|
||||
test-router-info-published:
|
||||
$(GO) test -v ./lib/common/router_info -run TestPublishedReturnsCorrectDate
|
||||
$(GO) test -v ./lib/common/router_info -run TestPublishedReturnsCorrectErrorWithPartialDate
|
||||
$(GO) test -v ./lib/common/router_info -run TestPublishedReturnsCorrectErrorWithInvalidData
|
||||
|
||||
test-router-info-addresses:
|
||||
$(GO) test -v ./lib/common/router_info -run TestRouterAddressCountReturnsCorrectCount
|
||||
$(GO) test -v ./lib/common/router_info -run TestRouterAddressCountReturnsCorrectErrorWithInvalidData
|
||||
$(GO) test -v ./lib/common/router_info -run TestRouterAddressesReturnsAddresses
|
||||
$(GO) test -v ./lib/common/router_info -run TestRouterAddressesReturnsAddressesWithMultiple
|
||||
|
||||
test-router-info-identity:
|
||||
$(GO) test -v ./lib/common/router_info -run TestRouterIdentityIsCorrect
|
||||
|
||||
test-router-info-misc:
|
||||
$(GO) test -v ./lib/common/router_info -run TestPeerSizeIsZero
|
||||
$(GO) test -v ./lib/common/router_info -run TestOptionsAreCorrect
|
||||
$(GO) test -v ./lib/common/router_info -run TestSignatureIsCorrectSize
|
||||
|
||||
.PHONY: test-router-info-all \
|
||||
test-router-info-published \
|
||||
test-router-info-addresses \
|
||||
test-router-info-identity \
|
||||
test-router-info-misc
|
27
doc/tests/string.mk
Normal file
27
doc/tests/string.mk
Normal file
@ -0,0 +1,27 @@
|
||||
test-string-all: test-string-length test-string-data test-string-conversion test-string-read
|
||||
|
||||
test-string-length:
|
||||
$(GO) test -v ./lib/common/data -run TestStringReportsCorrectLength
|
||||
$(GO) test -v ./lib/common/data -run TestI2PStringReportsLengthZeroError
|
||||
$(GO) test -v ./lib/common/data -run TestI2PStringReportsExtraDataError
|
||||
$(GO) test -v ./lib/common/data -run TestI2PStringDataReportsLengthZeroError
|
||||
|
||||
test-string-data:
|
||||
$(GO) test -v ./lib/common/data -run TestI2PStringDataReportsExtraDataError
|
||||
$(GO) test -v ./lib/common/data -run TestI2PStringDataEmptyWhenZeroLength
|
||||
$(GO) test -v ./lib/common/data -run TestI2PStringDataErrorWhenNonZeroLengthOnly
|
||||
|
||||
test-string-conversion:
|
||||
$(GO) test -v ./lib/common/data -run TestToI2PI2PStringFormatsCorrectly
|
||||
$(GO) test -v ./lib/common/data -run TestToI2PStringReportsOverflows
|
||||
|
||||
test-string-read:
|
||||
$(GO) test -v ./lib/common/data -run TestReadStringReadsLength
|
||||
$(GO) test -v ./lib/common/data -run TestReadI2PStringErrWhenEmptySlice
|
||||
$(GO) test -v ./lib/common/data -run TestReadI2PStringErrWhenDataTooShort
|
||||
|
||||
.PHONY: test-string-all \
|
||||
test-string-length \
|
||||
test-string-data \
|
||||
test-string-conversion \
|
||||
test-string-read
|
11
doc/tests/su3.mk
Normal file
11
doc/tests/su3.mk
Normal file
@ -0,0 +1,11 @@
|
||||
test-su3-all: test-su3-read test-su3-signature
|
||||
|
||||
test-su3-read:
|
||||
$(GO) test -v ./lib/su3 -run TestRead
|
||||
|
||||
test-su3-signature:
|
||||
$(GO) test -v ./lib/su3 -run TestReadSignatureFirst
|
||||
|
||||
.PHONY: test-su3-all \
|
||||
test-su3-read \
|
||||
test-su3-signature
|
22
doc/tests/tunnel.mk
Normal file
22
doc/tests/tunnel.mk
Normal file
@ -0,0 +1,22 @@
|
||||
test-tunnel-all: test-tunnel-delivery-instructions test-tunnel-message
|
||||
|
||||
# Tests from delivery_test.go
|
||||
test-tunnel-delivery-instructions:
|
||||
$(GO) test -v ./lib/tunnel -run TestReadDeliveryInstructions
|
||||
|
||||
# Tests from message_test.go
|
||||
test-tunnel-message: test-tunnel-message-padding test-tunnel-message-fragments
|
||||
|
||||
test-tunnel-message-padding:
|
||||
$(GO) test -v ./lib/tunnel -run TestDeliveryInstructionDataWithNoPadding
|
||||
$(GO) test -v ./lib/tunnel -run TestDeliveryInstructionDataWithSomePadding
|
||||
$(GO) test -v ./lib/tunnel -run TestDeliveryInstructionDataWithOnlyPadding
|
||||
|
||||
test-tunnel-message-fragments:
|
||||
$(GO) test -v ./lib/tunnel -run TestDeliveryInstructionsWithFragments
|
||||
|
||||
.PHONY: test-tunnel-all \
|
||||
test-tunnel-delivery-instructions \
|
||||
test-tunnel-message \
|
||||
test-tunnel-message-padding \
|
||||
test-tunnel-message-fragments
|
38
go.mod
38
go.mod
@ -1,11 +1,43 @@
|
||||
module github.com/go-i2p/go-i2p
|
||||
|
||||
go 1.16
|
||||
go 1.23.1
|
||||
|
||||
require (
|
||||
github.com/beevik/ntp v1.4.3
|
||||
github.com/emirpasic/gods v1.18.1
|
||||
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e
|
||||
github.com/flynn/noise v1.1.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/stretchr/testify v1.7.0
|
||||
golang.org/x/crypto v0.23.0
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
go.step.sm/crypto v0.53.0
|
||||
golang.org/x/crypto v0.27.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.7.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/net v0.29.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/text v0.18.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
)
|
||||
|
127
go.sum
127
go.sum
@ -1,71 +1,106 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho=
|
||||
github.com/beevik/ntp v1.4.3/go.mod h1:Unr8Zg+2dRn7d8bHFuehIMSvvUYssHMxW3Q5Nx4RW5Q=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/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.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
go.step.sm/crypto v0.53.0 h1:+1as1ogzuCzx15/468M4mEC5juogI5a0Fzbsyh1CuYY=
|
||||
go.step.sm/crypto v0.53.0/go.mod h1:AqLU78RqNUHepLzyOWZuNN/2++Lu7dZENdO9UzWOGSk=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.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/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.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/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-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/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
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/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
23
lib/bootstrap/doc.md
Normal file
23
lib/bootstrap/doc.md
Normal 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
33
lib/common/base32/doc.md
Normal 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
33
lib/common/base64/doc.md
Normal 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.
|
@ -3,13 +3,20 @@
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"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 +77,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 +101,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 +115,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 +135,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
|
||||
// readCertificate creates a new Certficiate from []byte
|
||||
// returns err if the certificate is too short or if the payload doesn't match specified length.
|
||||
func NewCertificate(data []byte) (certificate *Certificate, err error) {
|
||||
certificate = &Certificate{}
|
||||
func readCertificate(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()),
|
||||
@ -142,14 +173,14 @@ func NewCertificate(data []byte) (certificate *Certificate, err error) {
|
||||
default:
|
||||
certificate.kind = Integer(data[0:1])
|
||||
certificate.len = Integer(data[1:3])
|
||||
payleng := len(data) - CERT_MIN_SIZE
|
||||
payloadLength := len(data) - CERT_MIN_SIZE
|
||||
certificate.payload = data[CERT_MIN_SIZE:]
|
||||
if certificate.len.Int() > len(data)-CERT_MIN_SIZE {
|
||||
err = fmt.Errorf("certificate parsing warning: certificate data is shorter than specified by length")
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(Certificate) NewCertificate",
|
||||
"certificate_bytes_length": certificate.len.Int(),
|
||||
"certificate_payload_length": payleng,
|
||||
"certificate_payload_length": payloadLength,
|
||||
"data_bytes:": string(data),
|
||||
"kind_bytes": data[0:1],
|
||||
"len_bytes": data[1:3],
|
||||
@ -157,17 +188,75 @@ 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) {
|
||||
certificate, err = NewCertificate(data)
|
||||
func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, err error) {
|
||||
certificate, err = readCertificate(data)
|
||||
if err != nil && err.Error() == "certificate parsing warning: certificate data is longer than specified by length" {
|
||||
log.Warn("Certificate data longer than specified length")
|
||||
err = nil
|
||||
}
|
||||
remainder = certificate.ExcessBytes()
|
||||
log.WithFields(logrus.Fields{
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Read certificate and extracted remainder")
|
||||
return
|
||||
}
|
||||
|
||||
// NewCertificate creates a new Certificate with default NULL type
|
||||
func NewCertificate() *Certificate {
|
||||
return &Certificate{
|
||||
kind: Integer([]byte{CERT_NULL}),
|
||||
len: Integer([]byte{0}),
|
||||
payload: make([]byte, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// NewCertificateWithType creates a new Certificate with specified type and payload
|
||||
func NewCertificateWithType(certType uint8, payload []byte) (*Certificate, error) {
|
||||
// Validate certificate type
|
||||
switch certType {
|
||||
case CERT_NULL, CERT_HASHCASH, CERT_HIDDEN, CERT_SIGNED, CERT_MULTIPLE, CERT_KEY:
|
||||
// Valid type
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid certificate type: %d", certType)
|
||||
}
|
||||
|
||||
// For NULL certificates, payload should be empty
|
||||
if certType == CERT_NULL && len(payload) > 0 {
|
||||
return nil, errors.New("NULL certificates must have empty payload")
|
||||
}
|
||||
length, _ := NewIntegerFromInt(len(payload), 2)
|
||||
|
||||
cert := &Certificate{
|
||||
kind: Integer([]byte{certType}),
|
||||
len: *length,
|
||||
payload: make([]byte, len(payload)),
|
||||
}
|
||||
|
||||
// Copy payload if present
|
||||
if len(payload) > 0 {
|
||||
copy(cert.payload, payload)
|
||||
}
|
||||
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
func GetSignatureTypeFromCertificate(cert Certificate) (int, error) {
|
||||
if cert.Type() != CERT_KEY {
|
||||
return 0, fmt.Errorf("unexpected certificate type: %d", cert.Type)
|
||||
}
|
||||
if len(cert.payload) < 2 {
|
||||
return 0, fmt.Errorf("certificate payload too short to contain signature type")
|
||||
}
|
||||
sigType := int(binary.BigEndian.Uint16(cert.payload[0:2]))
|
||||
return sigType, nil
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ func TestCertificateTypeIsFirstByte(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
bytes := []byte{0x03, 0x00, 0x00}
|
||||
certificate, err := NewCertificate(bytes)
|
||||
certificate, err := readCertificate(bytes)
|
||||
cert_type := certificate.Type()
|
||||
|
||||
assert.Equal(cert_type, 3, "certificate.Type() should be the first bytes in a certificate")
|
||||
@ -21,7 +21,7 @@ func TestCertificateLengthCorrect(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff}
|
||||
certificate, err := NewCertificate(bytes)
|
||||
certificate, err := readCertificate(bytes)
|
||||
cert_len := certificate.Length()
|
||||
|
||||
assert.Equal(cert_len, 2, "certificate.Length() should return integer from second two bytes")
|
||||
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ func TestCertificateLengthErrWhenDataTooShort(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
bytes := []byte{0x03, 0x00, 0x02, 0xff}
|
||||
certificate, err := NewCertificate(bytes)
|
||||
certificate, err := readCertificate(bytes)
|
||||
cert_len := certificate.Length()
|
||||
|
||||
assert.Equal(cert_len, 2, "certificate.Length() did not return indicated length when data was actually missing")
|
||||
@ -58,7 +58,7 @@ func TestCertificateDataWhenCorrectSize(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
bytes := []byte{0x03, 0x00, 0x01, 0xaa}
|
||||
certificate, err := NewCertificate(bytes)
|
||||
certificate, err := readCertificate(bytes)
|
||||
cert_data := certificate.Data()
|
||||
|
||||
assert.Nil(err, "certificate.Data() returned error with valid data")
|
||||
@ -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")
|
||||
@ -88,7 +85,7 @@ func TestCertificateDataWhenTooShort(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
bytes := []byte{0x03, 0x00, 0x02, 0xff}
|
||||
certificate, err := NewCertificate(bytes)
|
||||
certificate, err := readCertificate(bytes)
|
||||
cert_data := certificate.Data()
|
||||
|
||||
if assert.NotNil(err) {
|
||||
@ -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")
|
||||
}
|
||||
}
|
||||
|
98
lib/common/certificate/doc.md
Normal file
98
lib/common/certificate/doc.md
Normal 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,
|
@ -5,9 +5,12 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
// DATE_SIZE is the length in bytes of an I2P Date.
|
||||
const DATE_SIZE = 8
|
||||
|
||||
@ -51,7 +54,7 @@ func (date Date) Time() (date_time time.Time) {
|
||||
// Any data after DATE_SIZE is returned as a remainder.
|
||||
func ReadDate(data []byte) (date Date, remainder []byte, err error) {
|
||||
if len(data) < 8 {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"data": data,
|
||||
}).Error("ReadDate: data is too short")
|
||||
err = errors.New("ReadDate: data is too short")
|
||||
@ -59,6 +62,10 @@ func ReadDate(data []byte) (date Date, remainder []byte, err error) {
|
||||
}
|
||||
copy(date[:], data[:8])
|
||||
remainder = data[8:]
|
||||
log.WithFields(logrus.Fields{
|
||||
"date_value": date.Int(),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully read Date from data")
|
||||
return
|
||||
}
|
||||
|
||||
@ -66,6 +73,15 @@ func ReadDate(data []byte) (date Date, remainder []byte, err error) {
|
||||
// Returns a pointer to Date unlike ReadDate.
|
||||
func NewDate(data []byte) (date *Date, remainder []byte, err error) {
|
||||
objdate, remainder, err := ReadDate(data)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new Date")
|
||||
return nil, remainder, err
|
||||
}
|
||||
|
||||
date = &objdate
|
||||
log.WithFields(logrus.Fields{
|
||||
"date_value": date.Int(),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully created new Date")
|
||||
return
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestTimeFromMiliseconds(t *testing.T) {
|
||||
func TestTimeFromMilliseconds(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
next_day := Date{0x00, 0x00, 0x00, 0x00, 0x05, 0x26, 0x5c, 0x00}
|
||||
|
297
lib/common/data/doc.md
Normal file
297
lib/common/data/doc.md
Normal 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
|
||||
```
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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,24 +138,24 @@ 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),
|
||||
}).Error("mapping format violation")
|
||||
log.Printf("DUPE: %s", key_str)
|
||||
log.Warnf("DUPE: %s", key_str)
|
||||
errs = append(errs, errors.New("mapping format violation, duplicate key in mapping"))
|
||||
// Based on other implementations this does not seem to happen often?
|
||||
// Java throws an exception in this case, the base object is a Hashmap so the value is overwritten and an exception is thrown.
|
||||
@ -142,13 +164,13 @@ 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),
|
||||
}).Warn("mapping format violation")
|
||||
errs = append(errs, errors.New("mapping format violation, expected ="))
|
||||
log.Printf("ERRVAL: %s", remainder)
|
||||
log.Warnf("ERRVAL: %s", remainder)
|
||||
break
|
||||
} else {
|
||||
remainder = remainder[1:]
|
||||
@ -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
|
||||
}
|
||||
|
@ -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,47 @@ 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) {
|
||||
length, _, err := NewInteger(data, 1)
|
||||
if err != nil {
|
||||
if len(data) == 0 {
|
||||
err = errors.New("data slice is empty")
|
||||
log.WithError(err).Error("Passed data with len == 0")
|
||||
return
|
||||
}
|
||||
data_len := length.Int()
|
||||
str = data[:data_len+1]
|
||||
remainder = data[data_len+1:]
|
||||
_, err = str.Length()
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(data),
|
||||
}).Debug("Reading I2PString from bytes")
|
||||
length, _, err := NewInteger(data, 1)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read I2PString length")
|
||||
return
|
||||
}
|
||||
data_len := length.Int() + 1
|
||||
if data_len > len(data) {
|
||||
err = fmt.Errorf("I2PString length %d exceeds available data %d", data_len-1, len(data)-1)
|
||||
log.WithError(err).Error("Failed to read I2PString")
|
||||
return
|
||||
}
|
||||
str = data[:data_len]
|
||||
remainder = data[data_len:]
|
||||
l, err := str.Length()
|
||||
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
|
||||
}
|
||||
}*/
|
||||
|
@ -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,57 @@ 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) {
|
||||
dest := destination.KeysAndCert.KeyCertificate.Bytes()
|
||||
log.Debug("Generating Base32 address for Destination")
|
||||
|
||||
cert := destination.KeysAndCert.Certificate()
|
||||
dest := cert.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 {
|
||||
dest := destination.KeysAndCert.KeyCertificate.Bytes()
|
||||
return base64.EncodeToString(dest)
|
||||
log.Debug("Generating Base64 address for Destination")
|
||||
|
||||
cert := destination.KeysAndCert.Certificate()
|
||||
dest := cert.Bytes()
|
||||
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
|
||||
}
|
||||
|
42
lib/common/destination/doc.md
Normal file
42
lib/common/destination/doc.md
Normal 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.
|
12
lib/common/fuzz/certificate/doc.md
Normal file
12
lib/common/fuzz/certificate/doc.md
Normal 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
|
||||
```
|
12
lib/common/fuzz/destination/doc.md
Normal file
12
lib/common/fuzz/destination/doc.md
Normal 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
|
||||
```
|
12
lib/common/fuzz/keys_and_cert/doc.md
Normal file
12
lib/common/fuzz/keys_and_cert/doc.md
Normal 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
|
||||
```
|
@ -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()
|
||||
|
12
lib/common/fuzz/router_address/doc.md
Normal file
12
lib/common/fuzz/router_address/doc.md
Normal 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
|
||||
```
|
12
lib/common/fuzz/router_identity/doc.md
Normal file
12
lib/common/fuzz/router_identity/doc.md
Normal 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
|
||||
```
|
@ -5,7 +5,7 @@ import common "github.com/go-i2p/go-i2p/lib/common/router_identity"
|
||||
func Fuzz(data []byte) int {
|
||||
router_identity, _, _ := common.ReadRouterIdentity(data)
|
||||
router_identity.Certificate()
|
||||
router_identity.PublicKey()
|
||||
router_identity.SigningPublicKey()
|
||||
// router_identity.publicKey()
|
||||
// router_identity.signingPublicKey()
|
||||
return 0
|
||||
}
|
||||
|
12
lib/common/fuzz/string/doc.md
Normal file
12
lib/common/fuzz/string/doc.md
Normal 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
|
||||
```
|
154
lib/common/key_certificate/doc.md
Normal file
154
lib/common/key_certificate/doc.md
Normal 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.
|
@ -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
|
||||
@ -62,7 +66,7 @@ const (
|
||||
KEYCERT_MIN_SIZE = 7
|
||||
)
|
||||
|
||||
// SigningPublicKey sizes for Signing Key Types
|
||||
// signingPublicKey sizes for Signing Key Types
|
||||
const (
|
||||
KEYCERT_SIGN_DSA_SHA1_SIZE = 128
|
||||
KEYCERT_SIGN_P256_SIZE = 64
|
||||
@ -75,7 +79,7 @@ const (
|
||||
KEYCERT_SIGN_ED25519PH_SIZE = 32
|
||||
)
|
||||
|
||||
// PublicKey sizes for Public Key Types
|
||||
// publicKey sizes for Public Key Types
|
||||
const (
|
||||
KEYCERT_CRYPTO_ELG_SIZE = 256
|
||||
KEYCERT_CRYPTO_P256_SIZE = 64
|
||||
@ -92,37 +96,52 @@ 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.
|
||||
// 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.
|
||||
// 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.
|
||||
// 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{
|
||||
"at": "(KeyCertificate) ConstructPublicKey",
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(keyCertificate) ConstructPublicKey",
|
||||
"data_len": data_len,
|
||||
"required_len": KEYCERT_PUBKEY_SIZE,
|
||||
"reason": "not enough data",
|
||||
@ -135,25 +154,35 @@ 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) {
|
||||
signing_key_type := key_certificate.PublicKeyType()
|
||||
log.WithFields(logrus.Fields{
|
||||
"input_length": len(data),
|
||||
}).Debug("Constructing signingPublicKey from keyCertificate")
|
||||
signing_key_type := key_certificate.SigningPublicKeyType()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data_len := len(data)
|
||||
if data_len < key_certificate.SignatureSize() {
|
||||
log.WithFields(log.Fields{
|
||||
"at": "(KeyCertificate) ConstructSigningPublicKey",
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(keyCertificate) ConstructSigningPublicKey",
|
||||
"data_len": data_len,
|
||||
"required_len": KEYCERT_SPK_SIZE,
|
||||
"reason": "not enough data",
|
||||
@ -166,35 +195,62 @@ 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
|
||||
var ec_p256_key crypto.ECP256PublicKey
|
||||
copy(ec_p256_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_P256_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = ec_p256_key
|
||||
log.Debug("Constructed P256PublicKey")
|
||||
case KEYCERT_SIGN_P384:
|
||||
var ec_key crypto.ECP384PublicKey
|
||||
copy(ec_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_P384_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = ec_key
|
||||
var ec_p384_key crypto.ECP384PublicKey
|
||||
copy(ec_p384_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_P384_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = ec_p384_key
|
||||
log.Debug("Constructed P384PublicKey")
|
||||
case KEYCERT_SIGN_P521:
|
||||
var ec_key crypto.ECP521PublicKey
|
||||
extra := KEYCERT_SIGN_P521_SIZE - KEYCERT_SPK_SIZE
|
||||
copy(ec_key[:], data)
|
||||
copy(ec_key[KEYCERT_SPK_SIZE:], key_certificate.Certificate.RawBytes()[4:4+extra])
|
||||
signing_public_key = ec_key
|
||||
/*var ec_p521_key crypto.ECP521PublicKey
|
||||
copy(ec_p521_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_P521_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = ec_p521_key
|
||||
log.Debug("Constructed P521PublicKey")*/
|
||||
panic("unimplemented P521SigningPublicKey")
|
||||
case KEYCERT_SIGN_RSA2048:
|
||||
//var rsa_key crypto.RSA2048PublicKey
|
||||
//extra := KEYCERT_SIGN_RSA2048_SIZE - 128
|
||||
//copy(rsa_key[:], data)
|
||||
//copy(rsa_key[128:], key_certificate[4:4+extra])
|
||||
//signing_public_key = rsa_key
|
||||
/*var rsa2048_key crypto.RSA2048PublicKey
|
||||
copy(rsa2048_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_RSA2048_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = rsa2048_key
|
||||
log.Debug("Constructed RSA2048PublicKey")*/
|
||||
panic("unimplemented RSA2048SigningPublicKey")
|
||||
case KEYCERT_SIGN_RSA3072:
|
||||
/*var rsa3072_key crypto.RSA3072PublicKey
|
||||
copy(rsa3072_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_RSA3072_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = rsa3072_key
|
||||
log.Debug("Constructed RSA3072PublicKey")*/
|
||||
panic("unimplemented RSA3072SigningPublicKey")
|
||||
case KEYCERT_SIGN_RSA4096:
|
||||
/*var rsa4096_key crypto.RSA4096PublicKey
|
||||
copy(rsa4096_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_RSA4096_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = rsa4096_key
|
||||
log.Debug("Constructed RSA4096PublicKey")*/
|
||||
panic("unimplemented RSA4096SigningPublicKey")
|
||||
case KEYCERT_SIGN_ED25519:
|
||||
var ed25519_key crypto.Ed25519PublicKey
|
||||
copy(ed25519_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_ED25519_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = ed25519_key
|
||||
log.Debug("Constructed Ed25519PublicKey")
|
||||
case KEYCERT_SIGN_ED25519PH:
|
||||
var ed25519ph_key crypto.Ed25519PublicKey
|
||||
copy(ed25519ph_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_ED25519PH_SIZE:KEYCERT_SPK_SIZE])
|
||||
signing_public_key = ed25519ph_key
|
||||
log.Debug("Constructed Ed25519PHPublicKey")
|
||||
default:
|
||||
log.WithFields(logrus.Fields{
|
||||
"signing_key_type": signing_key_type,
|
||||
}).Warn("Unknown signing key type")
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SignatureSize return the size of a Signature corresponding to the Key Certificate's SigningPublicKey type.
|
||||
// SignatureSize return the size of a Signature corresponding to the Key Certificate's signingPublicKey type.
|
||||
func (key_certificate KeyCertificate) SignatureSize() (size int) {
|
||||
sizes := map[int]int{
|
||||
KEYCERT_SIGN_DSA_SHA1: KEYCERT_SIGN_DSA_SHA1_SIZE,
|
||||
@ -208,10 +264,15 @@ 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)]
|
||||
}
|
||||
|
||||
// CryptoSize return the size of a Public Key corresponding to the Key Certificate's PublicKey type.
|
||||
// CryptoSize return the size of a Public Key corresponding to the Key Certificate's publicKey type.
|
||||
func (key_certificate KeyCertificate) CryptoSize() (size int) {
|
||||
sizes := map[int]int{
|
||||
KEYCERT_CRYPTO_ELG: KEYCERT_CRYPTO_ELG_SIZE,
|
||||
@ -221,6 +282,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 +294,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 {
|
||||
log.WithError(err).Error("keyCertificate data too short")
|
||||
err = errors.New("error parsing key certificate: not enough data")
|
||||
remainder = bytes[KEYCERT_MIN_SIZE:]
|
||||
}
|
||||
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
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ func TestPublicKeyTypeReturnsCorrectInteger(t *testing.T) {
|
||||
key_cert, _, err := NewKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03})
|
||||
pk_type := key_cert.PublicKeyType()
|
||||
|
||||
assert.Nil(err, "PublicKey() returned error with valid data")
|
||||
assert.Nil(err, "publicKey() returned error with valid data")
|
||||
assert.Equal(pk_type, KEYCERT_SIGN_P521, "PublicKeyType() did not return correct typec")
|
||||
}
|
||||
|
||||
@ -94,7 +94,7 @@ func TestConstructSigningPublicKeyWithDSASHA1(t *testing.T) {
|
||||
spk, err := key_cert.ConstructSigningPublicKey(data)
|
||||
|
||||
assert.Nil(err, "ConstructSigningPublicKey() with DSA SHA1 returned error with valid data")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_DSA_SHA1_SIZE, "ConstructSigningPublicKey() with DSA SHA1 returned incorrect SigningPublicKey length")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_DSA_SHA1_SIZE, "ConstructSigningPublicKey() with DSA SHA1 returned incorrect signingPublicKey length")
|
||||
}
|
||||
|
||||
func TestConstructSigningPublicKeyWithP256(t *testing.T) {
|
||||
@ -105,7 +105,7 @@ func TestConstructSigningPublicKeyWithP256(t *testing.T) {
|
||||
spk, err := key_cert.ConstructSigningPublicKey(data)
|
||||
|
||||
assert.Nil(err, "ConstructSigningPublicKey() with P256 returned err on valid data")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_P256_SIZE, "ConstructSigningPublicKey() with P256 returned incorrect SigningPublicKey length")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_P256_SIZE, "ConstructSigningPublicKey() with P256 returned incorrect signingPublicKey length")
|
||||
}
|
||||
|
||||
func TestConstructSigningPublicKeyWithP384(t *testing.T) {
|
||||
@ -116,16 +116,16 @@ func TestConstructSigningPublicKeyWithP384(t *testing.T) {
|
||||
spk, err := key_cert.ConstructSigningPublicKey(data)
|
||||
|
||||
assert.Nil(err, "ConstructSigningPublicKey() with P384 returned err on valid data")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_P384_SIZE, "ConstructSigningPublicKey() with P384 returned incorrect SigningPublicKey length")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_P384_SIZE, "ConstructSigningPublicKey() with P384 returned incorrect signingPublicKey length")
|
||||
}
|
||||
|
||||
func TestConstructSigningPublicKeyWithP521(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
key_cert, _, err := NewKeyCertificate([]byte{0x05, 0x00, 0x08, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00})
|
||||
data := make([]byte, 128)
|
||||
data := make([]byte, 132)
|
||||
spk, err := key_cert.ConstructSigningPublicKey(data)
|
||||
|
||||
assert.Nil(err, "ConstructSigningPublicKey() with P521 returned err on valid data")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_P521_SIZE, "ConstructSigningPublicKey() with P521 returned incorrect SigningPublicKey length")
|
||||
assert.Equal(spk.Len(), KEYCERT_SIGN_P521_SIZE, "ConstructSigningPublicKey() with P521 returned incorrect signingPublicKey length")
|
||||
}
|
||||
|
66
lib/common/keys_and_cert/doc.md
Normal file
66
lib/common/keys_and_cert/doc.md
Normal file
@ -0,0 +1,66 @@
|
||||
# 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.
|
@ -2,14 +2,19 @@
|
||||
package keys_and_cert
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"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
|
||||
@ -26,7 +31,7 @@ Description
|
||||
An encryption public key, a signing public key, and a certificate, used as either a RouterIdentity or a Destination.
|
||||
|
||||
Contents
|
||||
A PublicKey followed by a SigningPublicKey and then a Certificate.
|
||||
A publicKey followed by a signingPublicKey and then a Certificate.
|
||||
|
||||
+----+----+----+----+----+----+----+----+
|
||||
| public_key |
|
||||
@ -51,14 +56,14 @@ A PublicKey followed by a SigningPublicKey and then a Certificate.
|
||||
| certificate |
|
||||
+----+----+----+-//
|
||||
|
||||
public_key :: PublicKey (partial or full)
|
||||
public_key :: publicKey (partial or full)
|
||||
length -> 256 bytes or as specified in key certificate
|
||||
|
||||
padding :: random data
|
||||
length -> 0 bytes or as specified in key certificate
|
||||
padding length + signing_key length == 128 bytes
|
||||
|
||||
signing__key :: SigningPublicKey (partial or full)
|
||||
signing__key :: signingPublicKey (partial or full)
|
||||
length -> 128 bytes or as specified in key certificate
|
||||
padding length + signing_key length == 128 bytes
|
||||
|
||||
@ -72,116 +77,64 @@ total length: 387+ bytes
|
||||
//
|
||||
// https://geti2p.net/spec/common-structures#keysandcert
|
||||
type KeysAndCert struct {
|
||||
KeyCertificate *KeyCertificate
|
||||
keyCertificate *KeyCertificate
|
||||
publicKey crypto.PublicKey
|
||||
padding []byte
|
||||
Padding []byte
|
||||
signingPublicKey crypto.SigningPublicKey
|
||||
}
|
||||
|
||||
// Bytes returns the entire KeyCertificate in []byte form, trims payload to specified length.
|
||||
func (keys_and_cert *KeysAndCert) Bytes() []byte {
|
||||
return keys_and_cert.KeyCertificate.Bytes()
|
||||
// Bytes returns the entire keyCertificate in []byte form, trims payload to specified length.
|
||||
func (keys_and_cert KeysAndCert) Bytes() []byte {
|
||||
bytes := keys_and_cert.publicKey.Bytes()
|
||||
bytes = append(bytes, keys_and_cert.Padding...)
|
||||
bytes = append(bytes, keys_and_cert.signingPublicKey.Bytes()...)
|
||||
bytes = append(bytes, keys_and_cert.keyCertificate.Bytes()...)
|
||||
log.WithFields(logrus.Fields{
|
||||
"bytes_length": len(bytes),
|
||||
"pk_bytes_length": len(keys_and_cert.publicKey.Bytes()),
|
||||
"padding_bytes_length": len(keys_and_cert.Padding),
|
||||
"spk_bytes_length": len(keys_and_cert.signingPublicKey.Bytes()),
|
||||
"cert_bytes_length": len(keys_and_cert.keyCertificate.Bytes()),
|
||||
}).Debug("Retrieved bytes from KeysAndCert")
|
||||
return bytes
|
||||
}
|
||||
|
||||
// PublicKey returns the public key as a crypto.PublicKey.
|
||||
// publicKey returns the public key as a crypto.publicKey.
|
||||
func (keys_and_cert *KeysAndCert) PublicKey() (key crypto.PublicKey) {
|
||||
/*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.
|
||||
// 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) {
|
||||
return keys_and_cert.KeyCertificate.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,
|
||||
"reason": "not enough data",
|
||||
}).Error("error parsing keys and cert")
|
||||
err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
|
||||
keys_and_cert.KeyCertificate, remainder, _ = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
|
||||
keys_and_cert.keyCertificate, remainder, _ = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
|
||||
return
|
||||
} else if data_len < KEYS_AND_CERT_DATA_SIZE {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "ReadKeysAndCert",
|
||||
"data_len": data_len,
|
||||
"required_len": KEYS_AND_CERT_MIN_SIZE,
|
||||
@ -190,22 +143,110 @@ func NewKeysAndCert(data []byte) (keys_and_cert *KeysAndCert, remainder []byte,
|
||||
err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
|
||||
return
|
||||
}
|
||||
keys_and_cert.KeyCertificate, remainder, err = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
|
||||
keys_and_cert.keyCertificate, remainder, err = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
|
||||
if err != nil {
|
||||
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()])
|
||||
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])
|
||||
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
|
||||
keys_and_cert.Padding = padding
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"public_key_type": keys_and_cert.keyCertificate.PublicKeyType(),
|
||||
"signing_public_key_type": keys_and_cert.keyCertificate.SigningPublicKeyType(),
|
||||
"padding_length": len(padding),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully read KeysAndCert")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewKeysAndCert creates a new KeysAndCert instance with the provided parameters.
|
||||
// It validates the sizes of the provided keys and padding before assembling the struct.
|
||||
func NewKeysAndCert(
|
||||
keyCertificate *KeyCertificate,
|
||||
publicKey crypto.PublicKey,
|
||||
padding []byte,
|
||||
signingPublicKey crypto.SigningPublicKey,
|
||||
) (*KeysAndCert, error) {
|
||||
log.Debug("Creating new KeysAndCert with provided parameters")
|
||||
|
||||
// 1. Validate keyCertificate
|
||||
if keyCertificate == nil {
|
||||
log.Error("KeyCertificate is nil")
|
||||
return nil, errors.New("KeyCertificate cannot be nil")
|
||||
}
|
||||
|
||||
// 2. Validate publicKey size
|
||||
if publicKey.Len() != KEYS_AND_CERT_PUBKEY_SIZE {
|
||||
log.WithFields(logrus.Fields{
|
||||
"expected_size": KEYS_AND_CERT_PUBKEY_SIZE,
|
||||
"actual_size": publicKey.Len(),
|
||||
}).Error("Invalid publicKey size")
|
||||
return nil, errors.New("publicKey has an invalid size")
|
||||
}
|
||||
|
||||
/*
|
||||
// 3. Validate signingPublicKey size
|
||||
if signingPublicKey.Len() != KEYS_AND_CERT_SPK_SIZE {
|
||||
log.WithFields(logrus.Fields{
|
||||
"expected_size": KEYS_AND_CERT_SPK_SIZE,
|
||||
"actual_size": signingPublicKey.Len(),
|
||||
}).Error("Invalid signingPublicKey size")
|
||||
return nil, errors.New("signingPublicKey has an invalid size")
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
// 4. Validate padding size
|
||||
publicKeyLength := publicKey.Len()
|
||||
signingPublicKeyLength := signingPublicKey.Len()
|
||||
totalKeysSize := publicKeyLength + signingPublicKeyLength
|
||||
expectedPaddingSize := KEYS_AND_CERT_DATA_SIZE - totalKeysSize
|
||||
if len(padding) != expectedPaddingSize {
|
||||
log.WithFields(logrus.Fields{
|
||||
"expected_size": expectedPaddingSize,
|
||||
"actual_size": len(padding),
|
||||
}).Warn("Invalid padding size")
|
||||
// generate some random padding and continue
|
||||
padding = make([]byte, expectedPaddingSize)
|
||||
_, err := rand.Read(padding)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to generate random padding")
|
||||
return nil, err
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"expected_size": expectedPaddingSize,
|
||||
"actual_size": len(padding),
|
||||
}).Warn("Generated random padding")
|
||||
}
|
||||
|
||||
// 5. Assemble KeysAndCert
|
||||
keysAndCert := &KeysAndCert{
|
||||
keyCertificate: keyCertificate,
|
||||
publicKey: publicKey,
|
||||
Padding: padding,
|
||||
signingPublicKey: signingPublicKey,
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"public_key_length": publicKey.Len(),
|
||||
"signing_public_key_length": signingPublicKey.Len(),
|
||||
"padding_length": len(padding),
|
||||
}).Debug("Successfully created KeysAndCert")
|
||||
|
||||
return keysAndCert, nil
|
||||
}
|
||||
|
@ -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]))
|
||||
}
|
||||
|
18
lib/common/keys_and_cert/private_keys_and_cert.go
Normal file
18
lib/common/keys_and_cert/private_keys_and_cert.go
Normal 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
63
lib/common/lease/doc.md
Normal 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.
|
95
lib/common/lease_set/doc.md
Normal file
95
lib/common/lease_set/doc.md
Normal 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
|
@ -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
|
||||
@ -28,13 +32,13 @@ Accurate for version 0.9.49
|
||||
|
||||
Description
|
||||
Contains all of the currently authorized Leases for a particular Destination, the
|
||||
PublicKey to which garlic messages can be encrypted, and then the SigningPublicKey
|
||||
publicKey to which garlic messages can be encrypted, and then the signingPublicKey
|
||||
that can be used to revoke this particular version of the structure. The LeaseSet is one
|
||||
of the two structures stored in the network database (the other being RouterInfo), and
|
||||
is kered under the SHA256 of the contained Destination.
|
||||
|
||||
Contents
|
||||
Destination, followed by a PublicKey for encryption, then a SigningPublicKey which
|
||||
Destination, followed by a publicKey for encryption, then a signingPublicKey which
|
||||
can be used to revoke this version of the LeaseSet, then a 1 byte Integer specifying how
|
||||
many Lease structures are in the set, followed by the actual Lease structures and
|
||||
finally a Signature of the previous bytes signed by the Destination's SigningPrivateKey.
|
||||
@ -96,10 +100,10 @@ finally a Signature of the previous bytes signed by the Destination's SigningPri
|
||||
destination :: Destination
|
||||
length -> >= 387 bytes
|
||||
|
||||
encryption_key :: PublicKey
|
||||
encryption_key :: publicKey
|
||||
length -> 256 bytes
|
||||
|
||||
signing_key :: SigningPublicKey
|
||||
signing_key :: signingPublicKey
|
||||
length -> 128 bytes or as specified in destination's key certificate
|
||||
|
||||
num :: Integer
|
||||
@ -132,22 +136,28 @@ 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{
|
||||
"at": "(LeaseSet) PublicKey",
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(LeaseSet) publicKey",
|
||||
"data_len": remainder_len,
|
||||
"required_len": LEASE_SET_PUBKEY_SIZE,
|
||||
"reason": "not enough data",
|
||||
@ -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,
|
||||
@ -186,10 +200,11 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK
|
||||
}
|
||||
if cert_len == 0 {
|
||||
// No Certificate is present, return the LEASE_SET_SPK_SIZE byte
|
||||
// SigningPublicKey space as legacy DSA SHA1 SigningPublicKey.
|
||||
// signingPublicKey space as legacy DSA SHA1 signingPublicKey.
|
||||
var dsa_pk crypto.DSAPublicKey
|
||||
copy(dsa_pk[:], lease_set[offset:offset+LEASE_SET_SPK_SIZE])
|
||||
signing_public_key = dsa_pk
|
||||
log.Debug("Retrieved legacy DSA SHA1 signingPublicKey")
|
||||
} 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.
|
||||
// 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 +
|
||||
@ -325,19 +358,22 @@ func (lease_set LeaseSet) Verify() error {
|
||||
//data := lease_set[:data_end]
|
||||
//spk, _ := lease_set.
|
||||
// Destination().
|
||||
// SigningPublicKey()
|
||||
// signingPublicKey()
|
||||
//verifier, err := spk.NewVerifier()
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
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
|
||||
}
|
||||
|
@ -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 {
|
||||
@ -61,7 +61,7 @@ func buildSignature(size int) []byte {
|
||||
|
||||
func buildFullLeaseSet(n int) LeaseSet {
|
||||
lease_set_data := make([]byte, 0)
|
||||
lease_set_data = append(lease_set_data, buildDestination().KeysAndCert.KeyCertificate.RawBytes()...)
|
||||
lease_set_data = append(lease_set_data, buildDestination().KeysAndCert.Bytes()...)
|
||||
lease_set_data = append(lease_set_data, buildPublicKey()...)
|
||||
lease_set_data = append(lease_set_data, buildSigningKey()...)
|
||||
lease_set_data = append(lease_set_data, byte(n))
|
||||
@ -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)
|
||||
|
179
lib/common/router_address/doc.md
Normal file
179
lib/common/router_address/doc.md
Normal file
@ -0,0 +1,179 @@
|
||||
# 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) 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) 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
|
||||
|
||||
#### 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
|
||||
```
|
@ -2,10 +2,18 @@
|
||||
package router_address
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
. "github.com/go-i2p/go-i2p/lib/common/data"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Minimum number of bytes in a valid RouterAddress
|
||||
@ -13,6 +21,8 @@ const (
|
||||
ROUTER_ADDRESS_MIN_SIZE = 9
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
/*
|
||||
[RouterAddress]
|
||||
Accurate for version 0.9.49
|
||||
@ -63,47 +73,238 @@ 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()
|
||||
if err != nil {
|
||||
log.WithFields(log.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.TransportCost.Bytes()...)
|
||||
bytes = append(bytes, router_address.ExpirationDate.Bytes()...)
|
||||
bytes = append(bytes, router_address.TransportType...)
|
||||
bytes = append(bytes, router_address.TransportOptions.Data()...)
|
||||
log.WithField("bytes_length", len(bytes)).Debug("Converted RouterAddress to bytes")
|
||||
return bytes
|
||||
}
|
||||
|
||||
// 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 +316,95 @@ 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
|
||||
// NewRouterAddress creates a new RouterAddress with the provided parameters.
|
||||
// Returns a pointer to RouterAddress.
|
||||
func NewRouterAddress(cost uint8, expiration time.Time, transportType string, options map[string]string) (*RouterAddress, error) {
|
||||
log.Debug("Creating new RouterAddress")
|
||||
|
||||
// Create TransportCost as an Integer (1 byte)
|
||||
transportCost, err := NewIntegerFromInt(int(cost), 1)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create TransportCost Integer")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create ExpirationDate as a Date
|
||||
millis := expiration.UnixNano() / int64(time.Millisecond)
|
||||
dateBytes := make([]byte, DATE_SIZE)
|
||||
binary.BigEndian.PutUint64(dateBytes, uint64(millis))
|
||||
expirationDate, _, err := NewDate(dateBytes)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create ExpirationDate")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create TransportType as an I2PString
|
||||
transportTypeStr, err := ToI2PString(transportType)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create TransportType I2PString")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create TransportOptions as a Mapping
|
||||
transportOptions, err := GoMapToMapping(options)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create TransportOptions Mapping")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create RouterAddress
|
||||
ra := &RouterAddress{
|
||||
TransportCost: transportCost,
|
||||
ExpirationDate: expirationDate,
|
||||
TransportType: transportTypeStr,
|
||||
TransportOptions: transportOptions,
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"cost": cost,
|
||||
"expiration": expiration,
|
||||
"transportType": transportType,
|
||||
"options": options,
|
||||
}).Debug("Successfully created new RouterAddress")
|
||||
|
||||
return ra, nil
|
||||
}
|
||||
|
@ -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")
|
||||
|
28
lib/common/router_identity/doc.md
Normal file
28
lib/common/router_identity/doc.md
Normal 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.
|
@ -2,9 +2,16 @@
|
||||
package router_identity
|
||||
|
||||
import (
|
||||
"github.com/go-i2p/go-i2p/lib/common/certificate"
|
||||
"github.com/go-i2p/go-i2p/lib/common/key_certificate"
|
||||
. "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
/*
|
||||
[RouterIdentity]
|
||||
Accurate for version 0.9.49
|
||||
@ -20,24 +27,53 @@ 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,
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully read RouterIdentity")
|
||||
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
|
||||
return
|
||||
func NewRouterIdentity(publicKey crypto.PublicKey, signingPublicKey crypto.SigningPublicKey, cert certificate.Certificate, padding []byte) (*RouterIdentity, error) {
|
||||
log.Debug("Creating new RouterIdentity")
|
||||
|
||||
// Step 1: Create keyCertificate from the provided certificate.
|
||||
// Assuming NewKeyCertificate is a constructor that takes a Certificate and returns a keyCertificate.
|
||||
keyCert := key_certificate.KeyCertificateFromCertificate(cert)
|
||||
|
||||
// Step 2: Create KeysAndCert instance.
|
||||
keysAndCert, err := NewKeysAndCert(keyCert, publicKey, padding, signingPublicKey)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("NewKeysAndCert failed.")
|
||||
}
|
||||
|
||||
// Step 3: Initialize RouterIdentity with KeysAndCert.
|
||||
routerIdentity := RouterIdentity{
|
||||
KeysAndCert: *keysAndCert,
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"public_key_type": keyCert.PublicKeyType(),
|
||||
"signing_public_key_type": keyCert.SigningPublicKeyType(),
|
||||
"padding_length": len(padding),
|
||||
}).Debug("Successfully created RouterIdentity")
|
||||
|
||||
return &routerIdentity, nil
|
||||
}
|
||||
|
197
lib/common/router_info/10k_test.go
Normal file
197
lib/common/router_info/10k_test.go
Normal file
@ -0,0 +1,197 @@
|
||||
package router_info
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func consolidateNetDb(sourcePath string, destPath string) error {
|
||||
// Create destination directory if it doesn't exist
|
||||
if err := os.MkdirAll(destPath, 0o755); err != nil {
|
||||
return fmt.Errorf("failed to create destination directory: %v", err)
|
||||
}
|
||||
|
||||
// Walk through all subdirectories
|
||||
return filepath.Walk(sourcePath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("error accessing path %q: %v", path, err)
|
||||
}
|
||||
|
||||
// Skip if it's a directory
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if this is a routerInfo file
|
||||
if strings.HasPrefix(info.Name(), "routerInfo-") && strings.HasSuffix(info.Name(), ".dat") {
|
||||
// Create source file path
|
||||
srcFile := path
|
||||
|
||||
// Create destination file path
|
||||
dstFile := filepath.Join(destPath, info.Name())
|
||||
|
||||
// Copy the file
|
||||
if err := copyFile(srcFile, dstFile); err != nil {
|
||||
return fmt.Errorf("failed to copy %s: %v", info.Name(), err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) error {
|
||||
sourceFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer sourceFile.Close()
|
||||
|
||||
destFile, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
_, err = io.Copy(destFile, sourceFile)
|
||||
return err
|
||||
}
|
||||
|
||||
func consolidateAllNetDbs(tempDir string) error {
|
||||
// Common paths for I2P and I2Pd netDb
|
||||
i2pPath := filepath.Join(os.Getenv("HOME"), ".i2p/netDb")
|
||||
i2pdPath := filepath.Join(os.Getenv("HOME"), ".i2pd/netDb")
|
||||
|
||||
// Create the temp directory
|
||||
if err := os.MkdirAll(tempDir, 0o755); err != nil {
|
||||
return fmt.Errorf("failed to create temp directory: %v", err)
|
||||
}
|
||||
|
||||
// Try to consolidate I2P netDb
|
||||
if _, err := os.Stat(i2pPath); err == nil {
|
||||
if err := consolidateNetDb(i2pPath, tempDir); err != nil {
|
||||
fmt.Printf("Warning: Error processing I2P netDb: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Try to consolidate I2Pd netDb
|
||||
if _, err := os.Stat(i2pdPath); err == nil {
|
||||
if err := consolidateNetDb(i2pdPath, tempDir); err != nil {
|
||||
fmt.Printf("Warning: Error processing I2Pd netDb: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func cleanupTempDir(path string) error {
|
||||
if err := os.RemoveAll(path); err != nil {
|
||||
return fmt.Errorf("failed to cleanup temporary directory %s: %v", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createTempNetDbDir() (string, error) {
|
||||
// Get system's temp directory in a platform-independent way
|
||||
baseDir := os.TempDir()
|
||||
|
||||
// Create unique directory name with timestamp
|
||||
timestamp := time.Now().Unix()
|
||||
dirName := fmt.Sprintf("go-i2p-testfiles-%d", timestamp)
|
||||
|
||||
// Join paths in a platform-independent way
|
||||
tempDir := filepath.Join(baseDir, dirName)
|
||||
|
||||
// Create the directory with appropriate permissions
|
||||
err := os.MkdirAll(tempDir, 0o755)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create temporary directory: %v", err)
|
||||
}
|
||||
|
||||
return tempDir, nil
|
||||
}
|
||||
|
||||
func Test10K(t *testing.T) {
|
||||
i2pPath := filepath.Join(os.Getenv("HOME"), ".i2p/netDb")
|
||||
i2pdPath := filepath.Join(os.Getenv("HOME"), ".i2pd/netDb")
|
||||
|
||||
// Skip if neither directory exists
|
||||
if _, err := os.Stat(i2pPath); os.IsNotExist(err) {
|
||||
if _, err := os.Stat(i2pdPath); os.IsNotExist(err) {
|
||||
t.Skip("Neither .i2p nor .i2pd netDb directories exist, so we will skip.")
|
||||
}
|
||||
}
|
||||
|
||||
tempDir, err := createTempNetDbDir()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp directory: %v", err)
|
||||
}
|
||||
// defer cleanupTempDir(tempDir)
|
||||
|
||||
if err := consolidateAllNetDbs(tempDir); err != nil {
|
||||
t.Fatalf("Failed to consolidate netDbs: %v", err)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
targetDir, err := createTempNetDbDir()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Read and process all router info files
|
||||
files, err := os.ReadDir(tempDir)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read temp directory: %v", err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if !file.IsDir() && strings.HasPrefix(file.Name(), "routerInfo-") {
|
||||
// Read the router info file
|
||||
log.Println("RI LOAD: ", file.Name())
|
||||
data, err := os.ReadFile(filepath.Join(tempDir, file.Name()))
|
||||
if err != nil {
|
||||
t.Logf("Failed to read file %s: %v", file.Name(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse the router info
|
||||
// fmt.Printf("data: %s\n", string(data))
|
||||
routerInfo, _, err := ReadRouterInfo(data)
|
||||
if err != nil {
|
||||
t.Logf("Failed to parse router info from %s: %v", file.Name(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Write the router info to the target directory
|
||||
routerBytes, err := routerInfo.Bytes()
|
||||
if err != nil {
|
||||
t.Logf("Failed to serialize router info %s: %v", file.Name(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = os.WriteFile(filepath.Join(targetDir, file.Name()), routerBytes, 0o644)
|
||||
if err != nil {
|
||||
t.Logf("Failed to write router info %s: %v", file.Name(), err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
// Cleanup both directories
|
||||
if err := cleanupTempDir(tempDir); err != nil {
|
||||
log.WithError(err).Error("Failed to cleanup temp directory")
|
||||
t.Errorf("Failed to cleanup temp directory: %v", err)
|
||||
} else {
|
||||
log.Debug("Successfully cleaned up temp directory")
|
||||
}
|
||||
|
||||
if err := cleanupTempDir(targetDir); err != nil {
|
||||
log.WithError(err).Error("Failed to cleanup target directory")
|
||||
t.Errorf("Failed to cleanup target directory: %v", err)
|
||||
} else {
|
||||
log.Debug("Successfully cleaned up target directory")
|
||||
}
|
||||
}
|
139
lib/common/router_info/doc.md
Normal file
139
lib/common/router_info/doc.md
Normal file
@ -0,0 +1,139 @@
|
||||
# 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) 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
|
||||
```
|
@ -2,21 +2,33 @@
|
||||
package router_info
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/certificate"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
|
||||
"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 +114,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,10 +124,9 @@ 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
|
||||
bytes = append(bytes, router_info.router_identity.KeysAndCert.Bytes()...)
|
||||
func (router_info RouterInfo) Bytes() (bytes []byte, err error) {
|
||||
log.Debug("Converting RouterInfo to bytes")
|
||||
bytes = append(bytes, router_info.router_identity.Bytes()...)
|
||||
bytes = append(bytes, router_info.published.Bytes()...)
|
||||
bytes = append(bytes, router_info.size.Bytes()...)
|
||||
for _, router_address := range router_info.addresses {
|
||||
@ -123,21 +134,53 @@ 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
|
||||
}
|
||||
|
||||
// Convert a byte slice into a string like [1, 2, 3] -> "1, 2, 3"
|
||||
func bytesToString(bytes []byte) string {
|
||||
str := "["
|
||||
for i, b := range bytes {
|
||||
str += strconv.Itoa(int(b))
|
||||
if i < len(bytes)-1 {
|
||||
str += ", "
|
||||
}
|
||||
}
|
||||
str += "]"
|
||||
return str
|
||||
}
|
||||
|
||||
func (router_info RouterInfo) String() string {
|
||||
log.Debug("Converting RouterInfo to string")
|
||||
str := "Certificate: " + bytesToString(router_info.router_identity.Bytes()) + "\n"
|
||||
str += "Published: " + bytesToString(router_info.published.Bytes()) + "\n"
|
||||
str += "Addresses:" + bytesToString(router_info.size.Bytes()) + "\n"
|
||||
for index, router_address := range router_info.addresses {
|
||||
str += "Address " + strconv.Itoa(index) + ": " + router_address.String() + "\n"
|
||||
}
|
||||
str += "Peer Size: " + bytesToString(router_info.peer_size.Bytes()) + "\n"
|
||||
str += "Options: " + bytesToString(router_info.options.Data()) + "\n"
|
||||
str += "Signature: " + bytesToString([]byte(*router_info.signature)) + "\n"
|
||||
log.WithField("string_length", len(str)).Debug("Converted RouterInfo to string")
|
||||
return str
|
||||
}
|
||||
|
||||
// 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()
|
||||
cert := router_info.RouterIdentity().KeysAndCert.Certificate()
|
||||
data := cert.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 +190,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,131 +213,75 @@ 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")
|
||||
err = errors.New("error parsing router info: not enough data to read identity")
|
||||
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,
|
||||
"reason": "not enough data",
|
||||
}).Error("error parsing router info")
|
||||
err = errors.New("error parsing router info: not enough data")
|
||||
err = errors.New("error parsing router info: not enough data to read publish date")
|
||||
}
|
||||
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,
|
||||
"reason": "not enough data",
|
||||
}).Error("error parsing router address")
|
||||
err = errors.New("error parsing router info: not enough data")
|
||||
err = errors.New("error parsing router info: not enough data to read router addresses")
|
||||
}
|
||||
info.addresses = append(info.addresses, address)
|
||||
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,38 +293,176 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
|
||||
}
|
||||
err = errors.New("error parsing router info: " + estring)
|
||||
}
|
||||
sigType, err := certificate.GetSignatureTypeFromCertificate(info.router_identity.Certificate())
|
||||
log.WithFields(logrus.Fields{
|
||||
"sigType": sigType,
|
||||
}).Debug("Got sigType")
|
||||
info.signature, remainder, err = NewSignature(remainder, sigType)
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
log.WithFields(logrus.Fields{
|
||||
"at": "(RouterInfo) ReadRouterInfo",
|
||||
"data_len": len(remainder),
|
||||
//"required_len": MAPPING_SIZE,
|
||||
"reason": "not enough data",
|
||||
}).Error("error parsing router info")
|
||||
err = errors.New("error parsing router info: not enough data")
|
||||
err = errors.New("error parsing router info: not enough data to read signature")
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"router_identity": info.router_identity,
|
||||
"published": info.published,
|
||||
"address_count": len(info.addresses),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully read RouterInfo")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// serializeWithoutSignature serializes the RouterInfo up to (but not including) the signature.
|
||||
func (ri *RouterInfo) serializeWithoutSignature() []byte {
|
||||
var bytes []byte
|
||||
// Serialize RouterIdentity
|
||||
bytes = append(bytes, ri.router_identity.Bytes()...)
|
||||
|
||||
// Serialize Published Date
|
||||
bytes = append(bytes, ri.published.Bytes()...)
|
||||
|
||||
// Serialize Size
|
||||
bytes = append(bytes, ri.size.Bytes()...)
|
||||
|
||||
// Serialize Addresses
|
||||
for _, addr := range ri.addresses {
|
||||
bytes = append(bytes, addr.Bytes()...)
|
||||
}
|
||||
|
||||
// Serialize PeerSize (always zero)
|
||||
bytes = append(bytes, ri.peer_size.Bytes()...)
|
||||
|
||||
// Serialize Options
|
||||
bytes = append(bytes, ri.options.Data()...)
|
||||
|
||||
return bytes
|
||||
}
|
||||
|
||||
func NewRouterInfo(
|
||||
routerIdentity *RouterIdentity,
|
||||
publishedTime time.Time,
|
||||
addresses []*RouterAddress,
|
||||
options map[string]string,
|
||||
signingPrivateKey crypto.SigningPrivateKey,
|
||||
sigType int,
|
||||
) (*RouterInfo, error) {
|
||||
log.Debug("Creating new RouterInfo")
|
||||
|
||||
// 1. Create Published Date
|
||||
millis := publishedTime.UnixNano() / int64(time.Millisecond)
|
||||
dateBytes := make([]byte, DATE_SIZE)
|
||||
binary.BigEndian.PutUint64(dateBytes, uint64(millis))
|
||||
publishedDate, _, err := ReadDate(dateBytes)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Published Date")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. Create Size Integer
|
||||
sizeInt, err := NewIntegerFromInt(len(addresses), 1)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Size Integer")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 3. Create PeerSize Integer (always 0)
|
||||
peerSizeInt, err := NewIntegerFromInt(0, 1)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create PeerSize Integer")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 4. Convert options map to Mapping
|
||||
mapping, err := GoMapToMapping(options)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to convert options map to Mapping")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 5. Assemble RouterInfo without signature
|
||||
routerInfo := &RouterInfo{
|
||||
router_identity: *routerIdentity,
|
||||
published: &publishedDate,
|
||||
size: sizeInt,
|
||||
addresses: addresses,
|
||||
peer_size: peerSizeInt,
|
||||
options: mapping,
|
||||
signature: nil, // To be set after signing
|
||||
}
|
||||
|
||||
// 6. Serialize RouterInfo without signature
|
||||
dataBytes := routerInfo.serializeWithoutSignature()
|
||||
|
||||
// 7. Compute signature over serialized data
|
||||
signer, err := signingPrivateKey.NewSigner()
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create new signer")
|
||||
return nil, err
|
||||
}
|
||||
signatureBytes, err := signer.Sign(dataBytes)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to sign")
|
||||
}
|
||||
|
||||
// 8. Create Signature struct from signatureBytes
|
||||
sig, _, err := ReadSignature(signatureBytes, sigType)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Signature from signature bytes")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 9. Attach signature to RouterInfo
|
||||
routerInfo.signature = &sig
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"router_identity": routerIdentity,
|
||||
"published": publishedDate,
|
||||
"address_count": len(addresses),
|
||||
"options": options,
|
||||
"signature": sig,
|
||||
}).Debug("Successfully created RouterInfo")
|
||||
|
||||
return routerInfo, nil
|
||||
}
|
||||
|
||||
func (router_info *RouterInfo) RouterCapabilities() string {
|
||||
log.Debug("Retrieving RouterCapabilities")
|
||||
str, err := ToI2PString("caps")
|
||||
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 +473,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
|
||||
}
|
||||
|
113
lib/common/router_info/router_info2_test.go
Normal file
113
lib/common/router_info/router_info2_test.go
Normal file
@ -0,0 +1,113 @@
|
||||
package router_info
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/signature"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/common/certificate"
|
||||
"github.com/go-i2p/go-i2p/lib/common/data"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_address"
|
||||
"github.com/go-i2p/go-i2p/lib/common/router_identity"
|
||||
"github.com/go-i2p/go-i2p/lib/crypto"
|
||||
"golang.org/x/crypto/openpgp/elgamal"
|
||||
)
|
||||
|
||||
func TestCreateRouterInfo(t *testing.T) {
|
||||
// Generate signing key pair (Ed25519)
|
||||
var ed25519_privkey crypto.Ed25519PrivateKey
|
||||
_, err := (&ed25519_privkey).Generate()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate Ed25519 private key: %v\n", err)
|
||||
}
|
||||
ed25519_pubkey_raw, err := ed25519_privkey.Public()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to derive Ed25519 public key: %v\n", err)
|
||||
}
|
||||
ed25519_pubkey, ok := ed25519_pubkey_raw.(crypto.SigningPublicKey)
|
||||
if !ok {
|
||||
t.Fatalf("Failed to get SigningPublicKey from Ed25519 public key")
|
||||
}
|
||||
|
||||
// Generate encryption key pair (ElGamal)
|
||||
var elgamal_privkey elgamal.PrivateKey
|
||||
err = crypto.ElgamalGenerate(&elgamal_privkey, rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate ElGamal private key: %v\n", err)
|
||||
}
|
||||
|
||||
// Convert elgamal private key to crypto.ElgPrivateKey
|
||||
var elg_privkey crypto.ElgPrivateKey
|
||||
xBytes := elgamal_privkey.X.Bytes()
|
||||
if len(xBytes) > 256 {
|
||||
t.Fatalf("ElGamal private key X too large")
|
||||
}
|
||||
copy(elg_privkey[256-len(xBytes):], xBytes)
|
||||
|
||||
// Convert elgamal public key to crypto.ElgPublicKey
|
||||
var elg_pubkey crypto.ElgPublicKey
|
||||
yBytes := elgamal_privkey.PublicKey.Y.Bytes()
|
||||
if len(yBytes) > 256 {
|
||||
t.Fatalf("ElGamal public key Y too large")
|
||||
}
|
||||
copy(elg_pubkey[256-len(yBytes):], yBytes)
|
||||
|
||||
// Ensure that elg_pubkey implements crypto.PublicKey interface
|
||||
var _ crypto.PublicKey = elg_pubkey
|
||||
|
||||
// Create KeyCertificate specifying key types
|
||||
var payload bytes.Buffer
|
||||
|
||||
signingPublicKeyType, _ := data.NewIntegerFromInt(7, 2)
|
||||
cryptoPublicKeyType, _ := data.NewIntegerFromInt(0, 2)
|
||||
|
||||
err = binary.Write(&payload, binary.BigEndian, signingPublicKeyType)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write signing public key type to payload: %v\n", err)
|
||||
}
|
||||
|
||||
err = binary.Write(&payload, binary.BigEndian, cryptoPublicKeyType)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write crypto public key type to payload: %v\n", err)
|
||||
}
|
||||
|
||||
// Create KeyCertificate specifying key types
|
||||
cert, err := certificate.NewCertificateWithType(certificate.CERT_KEY, payload.Bytes())
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create new certificate: %v\n", err)
|
||||
}
|
||||
|
||||
// Create RouterIdentity
|
||||
routerIdentity, err := router_identity.NewRouterIdentity(elg_pubkey, ed25519_pubkey, *cert, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create router identity: %v\n", err)
|
||||
}
|
||||
// create some dummy addresses
|
||||
options := map[string]string{}
|
||||
routerAddress, err := router_address.NewRouterAddress(3, <-time.After(1*time.Second), "NTCP2", options)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create router address: %v\n", err)
|
||||
}
|
||||
routerAddresses := []*router_address.RouterAddress{routerAddress}
|
||||
// create router info
|
||||
routerInfo, err := NewRouterInfo(routerIdentity, time.Now(), routerAddresses, nil, &ed25519_privkey, signature.SIGNATURE_TYPE_EDDSA_SHA512_ED25519)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create router info: %v\n", err)
|
||||
}
|
||||
|
||||
t.Run("Serialize and Deserialize RouterInfo", func(t *testing.T) {
|
||||
routerInfoBytes, err := routerInfo.Bytes()
|
||||
t.Log(len(routerInfoBytes), routerInfo.String(), routerInfoBytes)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write RouterInfo to bytes: %v\n", err)
|
||||
}
|
||||
_, _, err = ReadRouterInfo(routerInfoBytes)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read routerInfoBytes: %v\n", err)
|
||||
}
|
||||
})
|
||||
}
|
@ -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(
|
||||
|
34
lib/common/session_key/doc.md
Normal file
34
lib/common/session_key/doc.md
Normal 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.
|
@ -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
|
||||
}
|
||||
|
34
lib/common/session_tag/doc.md
Normal file
34
lib/common/session_tag/doc.md
Normal 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.
|
@ -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
|
||||
}
|
||||
|
50
lib/common/signature/doc.md
Normal file
50
lib/common/signature/doc.md
Normal 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.
|
@ -1,6 +1,15 @@
|
||||
// Package signature implements the I2P Signature common data structure
|
||||
package signature
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"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
|
||||
@ -15,6 +24,19 @@ const (
|
||||
RedDSA_SHA512_Ed25519_SIZE = 64
|
||||
)
|
||||
|
||||
const (
|
||||
SIGNATURE_TYPE_DSA_SHA1 = 0
|
||||
SIGNATURE_TYPE_ECDSA_SHA256_P256 = 1
|
||||
SIGNATURE_TYPE_ECDSA_SHA384_P384 = 2
|
||||
SIGNATURE_TYPE_ECDSA_SHA512_P521 = 3
|
||||
SIGNATURE_TYPE_RSA_SHA256_2048 = 4
|
||||
SIGNATURE_TYPE_RSA_SHA384_3072 = 5
|
||||
SIGNATURE_TYPE_RSA_SHA512_4096 = 6
|
||||
SIGNATURE_TYPE_EDDSA_SHA512_ED25519 = 7
|
||||
SIGNATURE_TYPE_EDDSA_SHA512_ED25519PH = 8
|
||||
SIGNATURE_TYPE_REDDSA_SHA512_ED25519 = 11
|
||||
)
|
||||
|
||||
/*
|
||||
[Signature]
|
||||
Accurate for version 0.9.49
|
||||
@ -32,18 +54,51 @@ DSA_SHA1. As of release 0.9.12, other types may be supported, depending on conte
|
||||
// https://geti2p.net/spec/common-structures#signature
|
||||
type Signature []byte
|
||||
|
||||
// ReadSignature returns Signature from a []byte.
|
||||
// ReadSignature returns a Signature from a []byte.
|
||||
// The remaining bytes after the specified length are also returned.
|
||||
// Returns a list of errors that occurred during parsing.
|
||||
func ReadSignature(bytes []byte) (info Signature, remainder []byte, err error) {
|
||||
// TODO: stub
|
||||
// Returns an error if there is insufficient data to read the signature.
|
||||
//
|
||||
// Since the signature type and length are inferred from context (the type of key used),
|
||||
// and are not explicitly stated, this function assumes the default signature type (DSA_SHA1)
|
||||
// with a length of 40 bytes.
|
||||
//
|
||||
// If a different signature type is expected based on context, this function should be
|
||||
// modified accordingly to handle the correct signature length.
|
||||
func ReadSignature(data []byte, sigType int) (sig Signature, remainder []byte, err error) {
|
||||
var sigLength int
|
||||
switch sigType {
|
||||
case SIGNATURE_TYPE_DSA_SHA1:
|
||||
sigLength = DSA_SHA1_SIZE
|
||||
case SIGNATURE_TYPE_EDDSA_SHA512_ED25519:
|
||||
sigLength = EdDSA_SHA512_Ed25519_SIZE
|
||||
default:
|
||||
err = fmt.Errorf("unsupported signature type: %d", sigType)
|
||||
return
|
||||
}
|
||||
|
||||
if len(data) < sigLength {
|
||||
err = fmt.Errorf("insufficient data to read signature: need %d bytes, have %d", sigLength, len(data))
|
||||
log.WithError(err).Error("Failed to read Signature")
|
||||
return
|
||||
}
|
||||
sig = data[:sigLength]
|
||||
remainder = data[sigLength:]
|
||||
return
|
||||
}
|
||||
|
||||
// NewSignature creates a new *Signature from []byte using ReadSignature.
|
||||
// Returns a pointer to Signature unlike ReadSignature.
|
||||
func NewSignature(data []byte) (session_tag *Signature, remainder []byte, err error) {
|
||||
sessionTag, remainder, err := ReadSignature(data)
|
||||
session_tag = &sessionTag
|
||||
func NewSignature(data []byte, sigType int) (signature *Signature, remainder []byte, err error) {
|
||||
log.WithField("input_length", len(data)).Debug("Creating new Signature")
|
||||
sig, remainder, err := ReadSignature(data, sigType)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to read Signature")
|
||||
return nil, remainder, err
|
||||
}
|
||||
signature = &sig
|
||||
log.WithFields(logrus.Fields{
|
||||
"signature_length": len(sig),
|
||||
"remainder_length": len(remainder),
|
||||
}).Debug("Successfully created new Signature")
|
||||
return
|
||||
}
|
||||
|
113
lib/config/config.go
Normal file
113
lib/config/config.go
Normal file
@ -0,0 +1,113 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
CfgFile string
|
||||
log = logger.GetGoI2PLogger()
|
||||
)
|
||||
|
||||
const GOI2P_BASE_DIR = ".go-i2p"
|
||||
|
||||
func InitConfig() {
|
||||
defaultConfigDir := filepath.Join(os.Getenv("HOME"), GOI2P_BASE_DIR)
|
||||
defaultConfigFile := filepath.Join(defaultConfigDir, "config.yaml")
|
||||
|
||||
if CfgFile != "" {
|
||||
// Use config file from the flag
|
||||
viper.SetConfigFile(CfgFile)
|
||||
} else {
|
||||
// Create default config if it doesn't exist
|
||||
if _, err := os.Stat(defaultConfigFile); os.IsNotExist(err) {
|
||||
// Ensure directory exists
|
||||
if err := os.MkdirAll(defaultConfigDir, 0o755); err != nil {
|
||||
log.Fatalf("Could not create config directory: %s", err)
|
||||
}
|
||||
|
||||
// Create default configuration
|
||||
defaultConfig := struct {
|
||||
BaseDir string `yaml:"base_dir"`
|
||||
WorkingDir string `yaml:"working_dir"`
|
||||
NetDB NetDbConfig `yaml:"netdb"`
|
||||
Bootstrap BootstrapConfig `yaml:"bootstrap"`
|
||||
}{
|
||||
BaseDir: DefaultRouterConfig().BaseDir,
|
||||
WorkingDir: DefaultRouterConfig().WorkingDir,
|
||||
NetDB: *DefaultRouterConfig().NetDb,
|
||||
Bootstrap: *DefaultRouterConfig().Bootstrap,
|
||||
}
|
||||
|
||||
yamlData, err := yaml.Marshal(defaultConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not marshal default config: %s", err)
|
||||
}
|
||||
|
||||
// Write default config file
|
||||
if err := os.WriteFile(defaultConfigFile, yamlData, 0o644); err != nil {
|
||||
log.Fatalf("Could not write default config file: %s", err)
|
||||
}
|
||||
|
||||
log.Debugf("Created default configuration at: %s", defaultConfigFile)
|
||||
}
|
||||
|
||||
// Set up viper to use the config file
|
||||
viper.AddConfigPath(defaultConfigDir)
|
||||
viper.SetConfigName("config")
|
||||
viper.SetConfigType("yaml")
|
||||
}
|
||||
|
||||
// Load defaults
|
||||
setDefaults()
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
log.Warnf("Error reading config file: %s", err)
|
||||
} else {
|
||||
log.Debugf("Using config file: %s", viper.ConfigFileUsed())
|
||||
}
|
||||
|
||||
// Update RouterConfigProperties
|
||||
UpdateRouterConfig()
|
||||
}
|
||||
|
||||
func setDefaults() {
|
||||
// Router defaults
|
||||
viper.SetDefault("base_dir", DefaultRouterConfig().BaseDir)
|
||||
viper.SetDefault("working_dir", DefaultRouterConfig().WorkingDir)
|
||||
|
||||
// NetDb defaults
|
||||
viper.SetDefault("netdb.path", DefaultNetDbConfig.Path)
|
||||
|
||||
// Bootstrap defaults
|
||||
viper.SetDefault("bootstrap.low_peer_threshold", DefaultBootstrapConfig.LowPeerThreshold)
|
||||
viper.SetDefault("bootstrap.reseed_servers", []ReseedConfig{})
|
||||
}
|
||||
|
||||
func UpdateRouterConfig() {
|
||||
// Update Router configuration
|
||||
RouterConfigProperties.BaseDir = viper.GetString("base_dir")
|
||||
RouterConfigProperties.WorkingDir = viper.GetString("working_dir")
|
||||
|
||||
// Update NetDb configuration
|
||||
RouterConfigProperties.NetDb = &NetDbConfig{
|
||||
Path: viper.GetString("netdb.path"),
|
||||
}
|
||||
|
||||
// Update Bootstrap configuration
|
||||
var reseedServers []*ReseedConfig
|
||||
if err := viper.UnmarshalKey("bootstrap.reseed_servers", &reseedServers); err != nil {
|
||||
log.Warnf("Error parsing reseed servers: %s", err)
|
||||
reseedServers = []*ReseedConfig{}
|
||||
}
|
||||
|
||||
RouterConfigProperties.Bootstrap = &BootstrapConfig{
|
||||
LowPeerThreshold: viper.GetInt("bootstrap.low_peer_threshold"),
|
||||
ReseedServers: reseedServers,
|
||||
}
|
||||
}
|
85
lib/config/doc.md
Normal file
85
lib/config/doc.md
Normal 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
|
||||
```
|
@ -12,5 +12,5 @@ type NetDbConfig struct {
|
||||
|
||||
// default settings for netdb
|
||||
var DefaultNetDbConfig = NetDbConfig{
|
||||
Path: filepath.Join(".", "netDb"),
|
||||
Path: filepath.Join(defaultConfig(), "netDb"),
|
||||
}
|
||||
|
@ -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(), GOI2P_BASE_DIR, "base")
|
||||
}
|
||||
|
||||
func defaultConfig() string {
|
||||
return filepath.Join(home(), GOI2P_BASE_DIR, "config")
|
||||
}
|
||||
|
||||
// defaults for router
|
||||
var defaultRouterConfig = &RouterConfig{
|
||||
NetDb: &DefaultNetDbConfig,
|
||||
Bootstrap: &DefaultBootstrapConfig,
|
||||
BaseDir: defaultBase(),
|
||||
WorkingDir: defaultConfig(),
|
||||
}
|
||||
|
||||
func DefaultRouterConfig() *RouterConfig {
|
||||
return defaultRouterConfig
|
||||
}
|
||||
|
||||
var RouterConfigProperties = DefaultRouterConfig()
|
||||
|
@ -1 +1,177 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-i2p/go-i2p/lib/util/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logger.GetGoI2PLogger()
|
||||
|
||||
// AESSymmetricKey represents a symmetric key for AES encryption/decryption
|
||||
type AESSymmetricKey struct {
|
||||
Key []byte // AES key (must be 16, 24, or 32 bytes for AES-128, AES-192, AES-256)
|
||||
IV []byte // Initialization Vector (must be 16 bytes for AES)
|
||||
}
|
||||
|
||||
// AESSymmetricEncrypter implements the Encrypter interface using AES
|
||||
type AESSymmetricEncrypter struct {
|
||||
Key []byte
|
||||
IV []byte
|
||||
}
|
||||
|
||||
// Encrypt encrypts data using AES-CBC with PKCS#7 padding
|
||||
func (e *AESSymmetricEncrypter) Encrypt(data []byte) ([]byte, error) {
|
||||
log.WithField("data_length", len(data)).Debug("Encrypting data")
|
||||
|
||||
block, err := aes.NewCipher(e.Key)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create AES cipher")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plaintext := pkcs7Pad(data, aes.BlockSize)
|
||||
ciphertext := make([]byte, len(plaintext))
|
||||
mode := cipher.NewCBCEncrypter(block, e.IV)
|
||||
mode.CryptBlocks(ciphertext, plaintext)
|
||||
|
||||
log.WithField("ciphertext_length", len(ciphertext)).Debug("Data encrypted successfully")
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
// AESSymmetricDecrypter implements the Decrypter interface using AES
|
||||
type AESSymmetricDecrypter struct {
|
||||
Key []byte
|
||||
IV []byte
|
||||
}
|
||||
|
||||
// Decrypt decrypts data using AES-CBC with PKCS#7 padding
|
||||
func (d *AESSymmetricDecrypter) Decrypt(data []byte) ([]byte, error) {
|
||||
log.WithField("data_length", len(data)).Debug("Decrypting data")
|
||||
|
||||
block, err := aes.NewCipher(d.Key)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create AES cipher")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(data)%aes.BlockSize != 0 {
|
||||
log.Error("Ciphertext is not a multiple of the block size")
|
||||
return nil, fmt.Errorf("ciphertext is not a multiple of the block size")
|
||||
}
|
||||
|
||||
plaintext := make([]byte, len(data))
|
||||
mode := cipher.NewCBCDecrypter(block, d.IV)
|
||||
mode.CryptBlocks(plaintext, data)
|
||||
|
||||
plaintext, err = pkcs7Unpad(plaintext)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to unpad plaintext")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.WithField("plaintext_length", len(plaintext)).Debug("Data decrypted successfully")
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
// NewEncrypter creates a new AESSymmetricEncrypter
|
||||
func (k *AESSymmetricKey) NewEncrypter() (Encrypter, error) {
|
||||
log.Debug("Creating new AESSymmetricEncrypter")
|
||||
return &AESSymmetricEncrypter{
|
||||
Key: k.Key,
|
||||
IV: k.IV,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Len returns the length of the key
|
||||
func (k *AESSymmetricKey) Len() int {
|
||||
return len(k.Key)
|
||||
}
|
||||
|
||||
// NewDecrypter creates a new AESSymmetricDecrypter
|
||||
func (k *AESSymmetricKey) NewDecrypter() (Decrypter, error) {
|
||||
return &AESSymmetricDecrypter{
|
||||
Key: k.Key,
|
||||
IV: k.IV,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func pkcs7Pad(data []byte, blockSize int) []byte {
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
"block_size": blockSize,
|
||||
}).Debug("Applying PKCS#7 padding")
|
||||
|
||||
padding := blockSize - (len(data) % blockSize)
|
||||
padText := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
padded := append(data, padText...)
|
||||
|
||||
log.WithField("padded_length", len(padded)).Debug("PKCS#7 padding applied")
|
||||
return append(data, padText...)
|
||||
}
|
||||
|
||||
func pkcs7Unpad(data []byte) ([]byte, error) {
|
||||
log.WithField("data_length", len(data)).Debug("Removing PKCS#7 padding")
|
||||
|
||||
length := len(data)
|
||||
if length == 0 {
|
||||
log.Error("Data is empty")
|
||||
return nil, fmt.Errorf("data is empty")
|
||||
}
|
||||
padding := int(data[length-1])
|
||||
if padding == 0 || padding > aes.BlockSize {
|
||||
log.WithField("padding", padding).Error("Invalid padding")
|
||||
return nil, fmt.Errorf("invalid padding")
|
||||
}
|
||||
paddingStart := length - padding
|
||||
for i := paddingStart; i < length; i++ {
|
||||
if data[i] != byte(padding) {
|
||||
log.Error("Invalid padding")
|
||||
return nil, fmt.Errorf("invalid padding")
|
||||
}
|
||||
}
|
||||
|
||||
unpadded := data[:paddingStart]
|
||||
log.WithField("unpadded_length", len(unpadded)).Debug("PKCS#7 padding removed")
|
||||
return unpadded, nil
|
||||
}
|
||||
|
||||
// EncryptNoPadding encrypts data using AES-CBC without padding
|
||||
func (e *AESSymmetricEncrypter) EncryptNoPadding(data []byte) ([]byte, error) {
|
||||
if len(data)%aes.BlockSize != 0 {
|
||||
return nil, fmt.Errorf("data length must be a multiple of block size")
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(e.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ciphertext := make([]byte, len(data))
|
||||
mode := cipher.NewCBCEncrypter(block, e.IV)
|
||||
mode.CryptBlocks(ciphertext, data)
|
||||
|
||||
return ciphertext, nil
|
||||
}
|
||||
|
||||
// DecryptNoPadding decrypts data using AES-CBC without padding
|
||||
func (d *AESSymmetricDecrypter) DecryptNoPadding(data []byte) ([]byte, error) {
|
||||
if len(data)%aes.BlockSize != 0 {
|
||||
return nil, fmt.Errorf("data length must be a multiple of block size")
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(d.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plaintext := make([]byte, len(data))
|
||||
mode := cipher.NewCBCDecrypter(block, d.IV)
|
||||
mode.CryptBlocks(plaintext, data)
|
||||
|
||||
return plaintext, nil
|
||||
}
|
||||
|
182
lib/crypto/aes_test.go
Normal file
182
lib/crypto/aes_test.go
Normal file
@ -0,0 +1,182 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAESEncryptDecrypt(t *testing.T) {
|
||||
key := make([]byte, 32) // 256-bit key
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
_, err := rand.Read(key)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate random key: %v", err)
|
||||
}
|
||||
_, err = rand.Read(iv)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate random IV: %v", err)
|
||||
}
|
||||
|
||||
symmetricKey := AESSymmetricKey{
|
||||
Key: key,
|
||||
IV: iv,
|
||||
}
|
||||
|
||||
encrypter, err := symmetricKey.NewEncrypter()
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating encrypter: %v", err)
|
||||
}
|
||||
|
||||
decrypter, err := symmetricKey.NewDecrypter()
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating decrypter: %v", err)
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
plaintext []byte
|
||||
}{
|
||||
{"Empty string", []byte("")},
|
||||
{"Short string", []byte("Hello, World!")},
|
||||
{"Long string", bytes.Repeat([]byte("A"), 1000)},
|
||||
{"Exact block size", bytes.Repeat([]byte("A"), aes.BlockSize)},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ciphertext, err := encrypter.Encrypt(tc.plaintext)
|
||||
if err != nil {
|
||||
t.Fatalf("Encryption failed: %v", err)
|
||||
}
|
||||
|
||||
decrypted, err := decrypter.Decrypt(ciphertext)
|
||||
if err != nil {
|
||||
t.Fatalf("Decryption failed: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(tc.plaintext, decrypted) {
|
||||
t.Errorf("Decrypted text doesn't match original plaintext.\nOriginal: %s\nDecrypted: %s",
|
||||
hex.EncodeToString(tc.plaintext), hex.EncodeToString(decrypted))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAESEncryptInvalidKey(t *testing.T) {
|
||||
invalidKeys := [][]byte{
|
||||
make([]byte, 15), // Too short
|
||||
make([]byte, 17), // Invalid length
|
||||
make([]byte, 31), // Too short for AES-256
|
||||
make([]byte, 33), // Too long
|
||||
make([]byte, 0), // Empty
|
||||
nil, // Nil
|
||||
}
|
||||
|
||||
plaintext := []byte("Test plaintext")
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
_, _ = rand.Read(iv)
|
||||
|
||||
for _, key := range invalidKeys {
|
||||
symmetricKey := &AESSymmetricKey{
|
||||
Key: key,
|
||||
IV: iv,
|
||||
}
|
||||
encrypter, err := symmetricKey.NewEncrypter()
|
||||
if err == nil {
|
||||
_, err = encrypter.Encrypt(plaintext)
|
||||
}
|
||||
if err == nil {
|
||||
t.Errorf("Expected error for invalid key length %d, but got none", len(key))
|
||||
} else {
|
||||
t.Logf("Correctly got error for key length %d: %v", len(key), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAESDecryptInvalidInput(t *testing.T) {
|
||||
key := make([]byte, 32) // Valid key length for AES-256
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
_, _ = rand.Read(key)
|
||||
_, _ = rand.Read(iv)
|
||||
|
||||
symmetricKey := &AESSymmetricKey{
|
||||
Key: key,
|
||||
IV: iv,
|
||||
}
|
||||
decrypter, err := symmetricKey.NewDecrypter()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create decrypter: %v", err)
|
||||
}
|
||||
|
||||
invalidCiphertexts := [][]byte{
|
||||
make([]byte, 15), // Not a multiple of block size
|
||||
make([]byte, 0), // Empty
|
||||
nil, // Nil
|
||||
}
|
||||
|
||||
for _, ciphertext := range invalidCiphertexts {
|
||||
_, err := decrypter.Decrypt(ciphertext)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error for invalid ciphertext length %d, but got none", len(ciphertext))
|
||||
} else {
|
||||
t.Logf("Correctly got error for ciphertext length %d: %v", len(ciphertext), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPKCS7PadUnpad(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
input []byte
|
||||
blockSize int
|
||||
}{
|
||||
{"Empty input", []byte{}, 16},
|
||||
{"Exact block size", bytes.Repeat([]byte("A"), 16), 16},
|
||||
{"One byte short", bytes.Repeat([]byte("A"), 15), 16},
|
||||
{"Multiple blocks", bytes.Repeat([]byte("A"), 32), 16},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
padded := pkcs7Pad(tc.input, tc.blockSize)
|
||||
if len(padded)%tc.blockSize != 0 {
|
||||
t.Errorf("Padded data length (%d) is not a multiple of block size (%d)", len(padded), tc.blockSize)
|
||||
}
|
||||
|
||||
unpadded, err := pkcs7Unpad(padded)
|
||||
if err != nil {
|
||||
t.Fatalf("Unpadding failed: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(tc.input, unpadded) {
|
||||
t.Errorf("Unpadded data doesn't match original input.\nOriginal: %s\nUnpadded: %s",
|
||||
hex.EncodeToString(tc.input), hex.EncodeToString(unpadded))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPKCS7UnpadInvalidInput(t *testing.T) {
|
||||
invalidInputs := []struct {
|
||||
name string
|
||||
input []byte
|
||||
}{
|
||||
{"Empty slice", []byte{}},
|
||||
{"Invalid padding value", []byte{1, 2, 3, 4, 0}}, // Padding value 0 is invalid
|
||||
{"Padding larger than block size", append(bytes.Repeat([]byte{17}, 17))}, // Padding value 17 (>16) is invalid
|
||||
{"Incorrect padding bytes", []byte{1, 2, 3, 4, 5, 6, 2, 3, 3}}, // Last padding bytes do not match padding value
|
||||
{"Valid block size but invalid padding", append(bytes.Repeat([]byte{1}, 15), 3)}, // Padding value 3, but bytes are 1
|
||||
}
|
||||
|
||||
for _, tc := range invalidInputs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
_, err := pkcs7Unpad(tc.input)
|
||||
if err == nil {
|
||||
t.Errorf("Expected error for invalid input %v, but got none", tc.input)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
194
lib/crypto/curve25519.go
Normal file
194
lib/crypto/curve25519.go
Normal 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
|
||||
}
|
@ -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)
|
||||
|
688
lib/crypto/doc.md
Normal file
688
lib/crypto/doc.md
Normal file
@ -0,0 +1,688 @@
|
||||
# crypto
|
||||
--
|
||||
import "github.com/go-i2p/go-i2p/lib/crypto"
|
||||
|
||||
package for i2p specific cryptography
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
const (
|
||||
IPAD = byte(0x36)
|
||||
OPAD = byte(0x5C)
|
||||
)
|
||||
```
|
||||
#### type AESSymmetricKey
|
||||
```go
|
||||
type AESSymmetricKey struct {
|
||||
Key []byte // AES key (must be 16, 24, or 32 bytes for AES-128, AES-192, AES-256)
|
||||
IV []byte // Initialization Vector (must be 16 bytes for AES)
|
||||
}
|
||||
```
|
||||
|
||||
AESSymmetricKey represents a symmetric key for AES encryption/decryption
|
||||
|
||||
#### func (AESSymmetricKey) NewEncrypter
|
||||
|
||||
```go
|
||||
func (k *AESSymmetricKey) NewEncrypter() (Encrypter, error)
|
||||
```
|
||||
NewEncrypter creates a new AESSymmetricEncrypter
|
||||
|
||||
#### func (AESSymmetricKey) NewDecrypter
|
||||
|
||||
```go
|
||||
func (k *AESSymmetricKey) NewDecrypter() (Decrypter, error)
|
||||
```
|
||||
NewDecrypter creates a new AESSymmetricDecrypter
|
||||
|
||||
#### func (AESSymmetricKey) Len
|
||||
|
||||
```go
|
||||
func (k *AESSymmetricKey) Len() int
|
||||
```
|
||||
Len returns the length of the key
|
||||
|
||||
#### type AESSymmetricEncrypter
|
||||
|
||||
```go
|
||||
type AESSymmetricEncrypter struct {
|
||||
Key []byte
|
||||
IV []byte
|
||||
}
|
||||
```
|
||||
|
||||
AESSymmetricEncrypter implements the Encrypter interface using AES
|
||||
|
||||
#### func (*AESSymmetricEncrypter) Encrypt
|
||||
|
||||
```go
|
||||
func (e *AESSymmetricEncrypter) Encrypt(data []byte) ([]byte, error)
|
||||
```
|
||||
Encrypt encrypts data using AES-CBC with PKCS#7 padding
|
||||
|
||||
#### type AESSymmetricDecrypter
|
||||
|
||||
```go
|
||||
type AESSymmetricDecrypter struct {
|
||||
Key []byte
|
||||
IV []byte
|
||||
}
|
||||
```
|
||||
|
||||
AESSymmetricDecrypter implements the Decrypter interface using AES
|
||||
|
||||
#### func (*AESSymmetricDecrypter) Decrypt
|
||||
|
||||
```go
|
||||
func (d *AESSymmetricDecrypter) Decrypt(data []byte) ([]byte, error)
|
||||
```
|
||||
Decrypt decrypts data using AES-CBC with PKCS#7 padding
|
||||
```go
|
||||
var (
|
||||
ElgDecryptFail = errors.New("failed to decrypt elgamal encrypted data")
|
||||
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 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 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
|
@ -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
|
||||
}
|
||||
@ -81,8 +95,13 @@ type DSAVerifier struct {
|
||||
|
||||
type DSAPublicKey [128]byte
|
||||
|
||||
func (k DSAPublicKey) Bytes() []byte {
|
||||
return k[:]
|
||||
}
|
||||
|
||||
// create a new dsa verifier
|
||||
func (k DSAPublicKey) NewVerifier() (v Verifier, err error) {
|
||||
log.Debug("Creating new DSA verifier")
|
||||
v = &DSAVerifier{
|
||||
k: createDSAPublicKey(new(big.Int).SetBytes(k[:])),
|
||||
}
|
||||
@ -91,6 +110,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 +121,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 +155,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 +165,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 +207,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
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package crypto
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
@ -85,5 +84,5 @@ func BenchmarkDSASignVerify(b *testing.B) {
|
||||
fail++
|
||||
}
|
||||
}
|
||||
log.Infof("%d fails %d signs", fail, b.N)
|
||||
log.Debugf("%d fails %d signs", fail, b.N)
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type ECDSAVerifier struct {
|
||||
@ -14,15 +16,27 @@ type ECDSAVerifier struct {
|
||||
|
||||
// verify a signature given the hash
|
||||
func (v *ECDSAVerifier) VerifyHash(h, sig []byte) (err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"hash_length": len(h),
|
||||
"sig_length": len(sig),
|
||||
}).Debug("Verifying ECDSA signature hash")
|
||||
|
||||
r, s := elliptic.Unmarshal(v.c, sig)
|
||||
if r == nil || s == nil || !ecdsa.Verify(v.k, h, r, s) {
|
||||
log.Warn("Invalid ECDSA signature")
|
||||
err = ErrInvalidSignature
|
||||
} else {
|
||||
log.Debug("ECDSA signature verified successfully")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// verify a block of data by hashing it and comparing the hash against the signature
|
||||
func (v *ECDSAVerifier) Verify(data, sig []byte) (err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"data_length": len(data),
|
||||
"sig_length": len(sig),
|
||||
}).Debug("Verifying ECDSA signature")
|
||||
// sum the data and get the hash
|
||||
h := v.h.New().Sum(data)[len(data):]
|
||||
// verify
|
||||
@ -31,8 +45,13 @@ func (v *ECDSAVerifier) Verify(data, sig []byte) (err error) {
|
||||
}
|
||||
|
||||
func createECVerifier(c elliptic.Curve, h crypto.Hash, k []byte) (ev *ECDSAVerifier, err error) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"curve": c.Params().Name,
|
||||
"hash": h.String(),
|
||||
}).Debug("Creating ECDSA verifier")
|
||||
x, y := elliptic.Unmarshal(c, k[:])
|
||||
if x == nil {
|
||||
log.Error("Invalid ECDSA key format")
|
||||
err = ErrInvalidKeyFormat
|
||||
} else {
|
||||
ev = &ECDSAVerifier{
|
||||
@ -40,39 +59,76 @@ 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[:])
|
||||
func (k ECP256PublicKey) Bytes() []byte {
|
||||
return k[:]
|
||||
}
|
||||
|
||||
type ECP384PublicKey [96]byte
|
||||
type ECP384PrivateKey [48]byte
|
||||
func (k ECP256PublicKey) NewVerifier() (Verifier, error) {
|
||||
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
|
||||
ECP384PrivateKey [48]byte
|
||||
)
|
||||
|
||||
func (k ECP384PublicKey) Bytes() []byte {
|
||||
return k[:]
|
||||
}
|
||||
|
||||
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) Bytes() []byte {
|
||||
return k[:]
|
||||
}
|
||||
|
||||
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[:])
|
||||
}
|
||||
|
@ -8,9 +8,14 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var Ed25519EncryptTooBig = errors.New("failed to encrypt data, too big for Ed25519")
|
||||
var (
|
||||
Ed25519EncryptTooBig = errors.New("failed to encrypt data, too big for Ed25519")
|
||||
ErrInvalidPublicKeySize = errors.New("failed to verify: invalid ed25519 public key size")
|
||||
)
|
||||
|
||||
type Ed25519PublicKey []byte
|
||||
|
||||
@ -29,30 +34,53 @@ func (k Ed25519PublicKey) Len() int {
|
||||
return len(k)
|
||||
}
|
||||
|
||||
func (k Ed25519PublicKey) Bytes() []byte {
|
||||
return k
|
||||
}
|
||||
|
||||
func createEd25519PublicKey(data []byte) (k *ed25519.PublicKey) {
|
||||
log.WithField("data_length", len(data)).Debug("Creating Ed25519 public key")
|
||||
if len(data) == 256 {
|
||||
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
|
||||
}
|
||||
|
||||
func createEd25519Encryption(pub *ed25519.PublicKey, rand io.Reader) (enc *Ed25519Encryption, err error) {
|
||||
/*kbytes := make([]byte, 256)
|
||||
k := new(big.Int)
|
||||
for err == nil {
|
||||
_, err = io.ReadFull(rand, kbytes)
|
||||
k = new(big.Int).SetBytes(kbytes)
|
||||
k = k.Mod(k, pub.P)
|
||||
if k.Sign() != 0 {
|
||||
break
|
||||
}
|
||||
// createEd25519Encryption initializes the Ed25519Encryption struct using the public key.
|
||||
func createEd25519Encryption(pub *ed25519.PublicKey, randReader io.Reader) (*Ed25519Encryption, error) {
|
||||
// Define p = 2^255 - 19
|
||||
p := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 255), big.NewInt(19))
|
||||
|
||||
// Validate public key length
|
||||
if len(*pub) != ed25519.PublicKeySize {
|
||||
log.WithField("pub_length", len(*pub)).Error("Invalid Ed25519 public key size")
|
||||
return nil, ErrInvalidPublicKeySize
|
||||
}
|
||||
if err == nil {
|
||||
enc = &Ed25519Encryption{}
|
||||
}*/
|
||||
return
|
||||
|
||||
// Convert public key bytes to big.Int
|
||||
a := new(big.Int).SetBytes(*pub)
|
||||
|
||||
// Generate a random scalar b1 in [0, p)
|
||||
b1, err := rand.Int(randReader, p)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to generate b1 for Ed25519Encryption")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize Ed25519Encryption struct
|
||||
enc := &Ed25519Encryption{
|
||||
p: p,
|
||||
a: a,
|
||||
b1: b1,
|
||||
}
|
||||
|
||||
log.Debug("Ed25519Encryption created successfully")
|
||||
return enc, nil
|
||||
}
|
||||
|
||||
type Ed25519Encryption struct {
|
||||
@ -60,11 +88,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 +122,61 @@ 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[:])
|
||||
if k == nil {
|
||||
return nil, errors.New("invalid public key format")
|
||||
}
|
||||
|
||||
enc, err = createEd25519Encryption(k, rand.Reader)
|
||||
return
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to create Ed25519 encrypter")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debug("Ed25519 encrypter created successfully")
|
||||
return enc, nil
|
||||
}
|
||||
|
||||
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
|
||||
@ -121,12 +184,51 @@ func (v *Ed25519Verifier) Verify(data, sig []byte) (err error) {
|
||||
|
||||
type Ed25519PrivateKey ed25519.PrivateKey
|
||||
|
||||
func (k Ed25519PrivateKey) NewDecrypter() (Decrypter, error) {
|
||||
// TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (k Ed25519PrivateKey) NewSigner() (Signer, error) {
|
||||
if len(k) != ed25519.PrivateKeySize {
|
||||
return nil, errors.New("invalid ed25519 private key size")
|
||||
}
|
||||
return &Ed25519Signer{k: k}, nil
|
||||
}
|
||||
|
||||
func (k Ed25519PrivateKey) Len() int {
|
||||
return len(k)
|
||||
}
|
||||
|
||||
func (k *Ed25519PrivateKey) Generate() (SigningPrivateKey, error) {
|
||||
// Generate a new Ed25519 key pair
|
||||
_, priv, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Assign the generated private key to the receiver
|
||||
*k = Ed25519PrivateKey(priv)
|
||||
return k, nil
|
||||
}
|
||||
|
||||
func (k Ed25519PrivateKey) Public() (SigningPublicKey, error) {
|
||||
if len(k) != ed25519.PrivateKeySize {
|
||||
return nil, errors.New("invalid ed25519 private key size")
|
||||
}
|
||||
// The public key is the first 32 bytes of the private key's seed
|
||||
pubKey := k[32:]
|
||||
return Ed25519PublicKey(pubKey), nil
|
||||
}
|
||||
|
||||
type Ed25519Signer struct {
|
||||
k []byte
|
||||
}
|
||||
|
||||
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 +238,8 @@ func (s *Ed25519Signer) Sign(data []byte) (sig []byte, err error) {
|
||||
}
|
||||
|
||||
func (s *Ed25519Signer) SignHash(h []byte) (sig []byte, err error) {
|
||||
log.WithField("hash_length", len(h)).Debug("Signing hash with Ed25519")
|
||||
sig = ed25519.Sign(s.k, h)
|
||||
log.WithField("signature_length", len(sig)).Debug("Ed25519 signature created successfully")
|
||||
return
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"golang.org/x/crypto/openpgp/elgamal"
|
||||
)
|
||||
|
||||
@ -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,35 @@ 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) Bytes() []byte {
|
||||
return 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 +258,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
|
||||
}
|
||||
|
@ -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) {
|
||||
@ -45,8 +45,7 @@ func BenchmarkElgDecrypt(b *testing.B) {
|
||||
fails++
|
||||
}
|
||||
}
|
||||
log.Infof("%d fails %d rounds", fails, b.N)
|
||||
|
||||
log.Debugf("%d fails %d rounds", fails, b.N)
|
||||
}
|
||||
|
||||
func BenchmarkElgEncrypt(b *testing.B) {
|
||||
@ -69,7 +68,7 @@ func BenchmarkElgEncrypt(b *testing.B) {
|
||||
fails++
|
||||
}
|
||||
}
|
||||
log.Infof("%d fails %d rounds", fails, b.N)
|
||||
log.Debugf("%d fails %d rounds", fails, b.N)
|
||||
}
|
||||
|
||||
func TestElg(t *testing.T) {
|
||||
|
@ -8,7 +8,6 @@ type Encrypter interface {
|
||||
}
|
||||
|
||||
type PublicEncryptionKey interface {
|
||||
|
||||
// create a new encrypter to encrypt data to this public key
|
||||
NewEncrypter() (Encrypter, error)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -1,10 +1,61 @@
|
||||
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
|
||||
// Bytes implements SigningPublicKey.
|
||||
func (r RSA2048PublicKey) Bytes() []byte {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
type RSA4096PublicKey [512]byte
|
||||
type RSA4096PrivateKey [1024]byte
|
||||
// Len implements SigningPublicKey.
|
||||
func (r RSA2048PublicKey) Len() int {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// NewVerifier implements SigningPublicKey.
|
||||
func (r RSA2048PublicKey) NewVerifier() (Verifier, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
type (
|
||||
RSA3072PublicKey [384]byte
|
||||
RSA3072PrivateKey [786]byte
|
||||
)
|
||||
|
||||
// Bytes implements SigningPublicKey.
|
||||
func (r RSA3072PublicKey) Bytes() []byte {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// Len implements SigningPublicKey.
|
||||
func (r RSA3072PublicKey) Len() int {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// NewVerifier implements SigningPublicKey.
|
||||
func (r RSA3072PublicKey) NewVerifier() (Verifier, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
type (
|
||||
RSA4096PublicKey [512]byte
|
||||
RSA4096PrivateKey [1024]byte
|
||||
)
|
||||
|
||||
// Bytes implements SigningPublicKey.
|
||||
func (r RSA4096PublicKey) Bytes() []byte {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// Len implements SigningPublicKey.
|
||||
func (r RSA4096PublicKey) Len() int {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// NewVerifier implements SigningPublicKey.
|
||||
func (r RSA4096PublicKey) NewVerifier() (Verifier, error) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user