146 Commits

Author SHA1 Message Date
idk
344edc6d41 Merge branch 'master' into noise-experimental 2024-11-02 02:59:24 +00:00
idk
9eea99b489 Merge pull request #20 from hkh4n/noise-experimental
Polishes
2024-11-01 14:30:25 +00:00
idk
c984f94b90 Merge pull request #9 from hkh4n/sntp-experimental
Implemented mimic implementation of sntp from the original java implementation
2024-11-01 14:28:00 +00:00
Haris Khan
a17f0208dd gofumpt adjustment 2024-10-31 10:53:22 -04:00
Haris Khan
487815f8f1 tests 2024-10-31 10:50:21 -04:00
Haris Khan
24e0baa879 Moved functions
-encryptPacketDeux -> testEncryptPacket in encrdecr_packet_test.go
-decryptPacketDeux -> testDecryptPacket in encrdecr_packet_test.go
2024-10-31 10:45:42 -04:00
Haris Khan
a5d2f0de8c lib/transport/noise/doc.md 2024-10-31 00:01:22 -04:00
Haris Khan
423f616d53 Info -> Debug 2024-10-30 23:29:46 -04:00
idk
c65048f3c4 Merge pull request #18 from hkh4n/config
Added config
2024-10-30 22:03:24 +00:00
Haris Khan
39b683dac8 fixed circular dependency 2024-10-30 11:20:15 -04:00
Haris Khan
46883f6457 build fails -> import cycle 2024-10-30 09:31:01 -04:00
Haris Khan
4be55062fc Moved config funcs to config.go 2024-10-30 09:22:32 -04:00
Haris Khan
12a3fd4623 Added config files + args
-added routerInstance
-added initConfig()
-added updateRouterConfig()
-yaml format
2024-10-30 09:16:22 -04:00
eyedeekay
80e539930e Mapping: fix off-by-one. Format: gofumpt 2024-10-28 18:11:54 -04:00
Haris Khan
e58d326d89 Move obfuscation functions to lib/transport/ntcp 2024-10-25 21:29:02 -04:00
Haris Khan
e6f84c16f6 added experimental functions which factor in packet length
-encryptPacketDeux
-decryptPacketDeux

Added test -> TestEncryptDecryptPacketObfsOfflineWithFunc()

added new functions in aes.go
-EncryptNoPadding
-DecryptNoPadding
2024-10-24 22:57:36 -04:00
Haris Khan
971a18de8d added Compatible warning message 2024-10-24 19:23:36 -04:00
Haris Khan
833836ae67 added TestEncryptDecryptPacketObfsOffline 2024-10-24 18:58:07 -04:00
Haris Khan
3f191db37a implement TODO for Compatible in NoiseTransport 2024-10-24 18:03:20 -04:00
idk
6865bae386 Merge pull request #17 from hkh4n/dirs
create ~/go-i2p and ~/go-i2p/config properly
2024-10-24 20:12:06 +00:00
Haris Khan
f0d9f89ed9 Mkdir -> MkdirAll 2024-10-24 14:26:51 -04:00
idk
c149eef1de Merge pull request #15 from hkh4n/makefile
Makefiles for tests + hotfix for logging naming convention
2024-10-23 17:34:06 +00:00
Haris Khan
748dc8a66f tweaks 2024-10-23 00:11:46 -04:00
Haris Khan
677aac500e fix logger naming collision with other libs 2024-10-23 00:06:06 -04:00
Haris Khan
4e06d3d5ed makefiles 2024-10-22 22:31:19 -04:00
Haris Khan
5eaa9cf588 log name collision fix 2024-10-22 22:10:14 -04:00
Haris Khan
4dbf537e94 log name collision fix 2024-10-22 22:07:39 -04:00
Haris Khan
882c018c0c log name collision fix 2024-10-22 22:06:06 -04:00
Haris Khan
5432502852 typo correction 2024-10-22 21:43:49 -04:00
idk
0ea5743365 Merge pull request #14 from hkh4n/noise-experimental
gofumpt adjustment
2024-10-22 21:53:24 +00:00
Haris Khan
a9dc482bda gofumpt 2024-10-22 17:37:17 -04:00
idk
c31d20fec0 Merge pull request #13 from hkh4n/logging
Logging
2024-10-22 18:55:15 +00:00
Haris Khan
647546a374 typo fix 2024-10-22 14:51:17 -04:00
Haris Khan
e468520906 Merge branch 'master' into sntp-experimental 2024-10-20 00:09:42 -04:00
Haris Khan
ade80e577c added sntp verification
-Leap Indicator
-Stratum level check
-Round-trip Delay
-Clock offset
-simple non-zero time
-Root Dispersion and Root Delay
2024-10-20 00:07:40 -04:00
Haris Khan
f45d301868 proposed refactor
-added secureRandBool() and performTimeQuery()
2024-10-19 22:17:10 -04:00
Haris Khan
0256908395 CRITICAL FIX, bytesRead -> n.
n wasn't being used before
2024-10-19 17:27:39 -04:00
Haris Khan
3c5aa206d1 expanded logging in message.go 2024-10-19 12:32:49 -04:00
Haris Khan
a4517cafd7 expanded logging in delivery.go 2024-10-19 12:25:31 -04:00
Haris Khan
f4f39ca53c expanded logging in multi.go 2024-10-19 11:18:20 -04:00
Haris Khan
220159476a expanded logging in write_session.go 2024-10-19 11:09:37 -04:00
Haris Khan
792cd49208 expanded logging in transport.go 2024-10-19 11:03:55 -04:00
Haris Khan
68051630c0 expanded logging in session.go 2024-10-19 10:55:30 -04:00
Haris Khan
a3340eb40a expanded logging in read_session.go + changed structure in readPacketLocked() 2024-10-19 10:50:13 -04:00
Haris Khan
465a7787a9 expanded logging in outgoing_handshake.go 2024-10-19 10:44:08 -04:00
Haris Khan
af3bc44dba expanded logging in incoming_handshake.go 2024-10-19 10:39:23 -04:00
Haris Khan
f850f482cf expanded logging in handshake.go 2024-10-19 10:30:11 -04:00
Haris Khan
3f23376d22 expanded logging in su3.go 2024-10-19 10:19:55 -04:00
Haris Khan
aa98589f1c expanded logging in router.go 2024-10-19 09:46:23 -04:00
Haris Khan
c31e990995 expanded logging in std.go 2024-10-18 23:06:44 -04:00
Haris Khan
8e97eb5f77 expanded logging in reseed.go 2024-10-18 22:54:08 -04:00
Haris Khan
be35267079 expanded logging in header.go 2024-10-18 22:47:28 -04:00
Haris Khan
013d35b447 expanded logging in build_request_record.go 2024-10-18 22:41:40 -04:00
Haris Khan
e8c9dc17a3 expanded logging in tunnel.go 2024-10-18 21:58:50 -04:00
Haris Khan
a1d574446b expanded logging in elg.go 2024-10-18 21:54:27 -04:00
Haris Khan
8680acc595 expanded logging in ed25519.go 2024-10-18 21:42:07 -04:00
Haris Khan
84e3c5accc expanded logging in ecdsa.go 2024-10-18 17:01:42 -04:00
Haris Khan
e772fb5ceb expanded logging in dsa.go 2024-10-18 16:56:25 -04:00
Haris Khan
a533cd7ce4 expanded logging in curve25519.go 2024-10-18 16:39:28 -04:00
Haris Khan
df37d49444 expanded logging to aes.go 2024-10-18 15:10:16 -04:00
Haris Khan
4b2600a065 expanded logging to signature.go
-changed sessionTag -> sig
2024-10-18 14:55:30 -04:00
Haris Khan
1c4f937002 expanded logging to session_tag.go 2024-10-18 14:51:53 -04:00
Haris Khan
5c2b408f65 expanded logging to session_key.go 2024-10-18 14:43:59 -04:00
Haris Khan
beb533a09b expanded logging to router_info.go 2024-10-18 14:40:52 -04:00
Haris Khan
f022522ad5 expanded logging to router_identity.go 2024-10-18 14:27:41 -04:00
Haris Khan
2191c40ac6 expanded logging to router_address.go + gofumpt adjustment 2024-10-18 13:22:36 -04:00
Haris Khan
3bca467f28 updated README.md to reflect new logging paradigm. 2024-10-18 12:59:49 -04:00
Haris Khan
a2fd65ee32 expanded logging in lease_set.go 2024-10-18 12:55:35 -04:00
Haris Khan
b894e8fb17 expanded logging in keys_and_cert.go 2024-10-18 12:41:48 -04:00
Haris Khan
93a71c7398 expanded logging in key_certificate.go 2024-10-18 12:27:42 -04:00
Haris Khan
b6544ad194 expanded logging in destination.go 2024-10-18 12:16:36 -04:00
Haris Khan
a72b61a886 expanded logging in string.go 2024-10-18 12:08:27 -04:00
Haris Khan
dda4f90b6f expanded logging in mapping_values.go 2024-10-18 12:00:58 -04:00
Haris Khan
1d1d8126c2 adjusted logging in main.go 2024-10-18 11:53:01 -04:00
Haris Khan
73db39ae50 expanded logging in mapping.go 2024-10-18 11:52:39 -04:00
Haris Khan
53e902f491 expanded logging to date.go 2024-10-18 11:49:10 -04:00
Haris Khan
2f2cd2249c expanded logging to certificate.go 2024-10-18 11:48:56 -04:00
Haris Khan
4496c11394 added lib/util/logger/log.go 2024-10-17 22:03:46 -04:00
idk
69449a20b5 Merge pull request #12 from hkh4n/crypto2
AES
2024-10-17 23:48:13 +00:00
Haris Khan
a7689e801a minor typo 2024-10-06 12:13:04 -04:00
Haris Khan
278bdee277 Various changes
-Aes -> AES
-doc.md
2024-10-06 10:48:22 -04:00
Haris Khan
684e89c957 minor typo 2024-10-05 10:15:31 -04:00
Haris Khan
50fa9fc374 gofumpt adjustment 2024-10-05 09:43:58 -04:00
Haris Khan
491b25022e AES
-Revamped encrypt and decrypt to fit with interfaces
-Adjusted test cases for TestPKCS7UnpadInvalidInput()
2024-10-05 09:00:33 -04:00
Haris Khan
677a6b354b AES test 2024-10-04 22:37:57 -04:00
Haris Khan
9469fd83aa AES 2024-10-04 22:36:32 -04:00
idk
8173ae49e6 Merge pull request #10 from hkh4n/makefile
Added gofumpt check
2024-10-04 03:26:01 +00:00
Haris Khan
2f109d5b4d Added gofumpt check 2024-10-03 23:24:12 -04:00
eyedeekay
d7378d7b08 more merge conflicts 2024-10-03 22:46:39 -04:00
eyedeekay
3a51a1229e more merge conflicts 2024-10-03 22:45:33 -04:00
eyedeekay
2b18b2941d resolve merge conflicts in lib/transport/noise 2024-10-03 22:42:00 -04:00
eyedeekay
1eb29ec4ab formatting issues only 2024-10-03 22:36:23 -04:00
eyedeekay
d900d7faf8 add doc.md files from master 2024-10-03 22:10:55 -04:00
eyedeekay
03c9d60ab9 update other non-transport parts of lib 2024-10-03 22:09:16 -04:00
eyedeekay
de2caf499e use makefile from Master 2024-10-03 21:58:16 -04:00
eyedeekay
284dd7287e use makefile from Master 2024-10-03 21:56:58 -04:00
eyedeekay
9f4154ff45 gofmt 2024-10-03 21:55:35 -04:00
eyedeekay
08a0d92742 gofmt 2024-10-03 21:52:49 -04:00
eyedeekay
524526d946 Bring in crypto stubs from master 2024-10-03 21:41:31 -04:00
eyedeekay
09c7d32797 update the common library to the master branch 2024-10-03 21:31:54 -04:00
Haris Khan
16961abc96 !WIP!
-added error handling in TestTransport()
-fixed typo to ComposeReceiverHandshakeMessage
-experimental implementation of encryptPacket
-added encrdecr_packet_test.go
2024-10-03 19:45:17 -04:00
Haris Khan
8fa355f067 !WIP! router_timestamper 2024-09-29 22:03:30 -04:00
eyedeekay
0c7a3f0f22 force static builds for slightly easier debugging 2024-09-09 20:13:20 -04:00
eyedeekay
3d535f67a1 Work on curve25519 stuff so I can generate my own routerInfos instead of just sending crap to other people 2024-09-09 20:10:38 -04:00
eyedeekay
bba9350506 WOO some of the important fields are actually populated with correct values 2024-08-28 20:47:54 -04:00
eyedeekay
cbc0de4e7e Start working on de-obfuscating ephemeral keys from remote peers 2024-08-28 18:32:42 -04:00
eyedeekay
310ef07d3c generate godoc locally so I can go over it offline 2024-08-26 16:21:54 -04:00
eyedeekay
14fc6fc3a8 Work on noise tools, comment details of handshake stuff 2024-08-25 23:22:21 -04:00
eyedeekay
a3ce9d36c6 If string data is shorter than specified by length create a new string based on the content after the first byte 2024-07-08 10:46:16 -04:00
eyedeekay
58a43cdfaf Fix string length checks, sortof 2024-07-05 23:12:03 -04:00
eyedeekay
15a5ca5daf Try and make noise work and also fix some tests 2024-07-05 18:12:58 -04:00
eyedeekay
08a41686b6 Work on noise wrapper. It is now good enough to fail to connect to a remote I2P router in a way which is discernible on that remote router. 2024-07-03 01:19:31 -04:00
eyedeekay
8318fd8f57 Work on noise wrapper. It is now good enough to fail to connect to a remote I2P router in a way which is discernible on that remote router. 2024-07-03 01:17:36 -04:00
eyedeekay
9c0552e236 Make some netDb loading stuff work so I have RI's to talk to 2024-07-02 16:54:30 -04:00
eyedeekay
20b018a708 Make some netDb loading stuff work so I have RI's to talk to 2024-07-02 16:53:57 -04:00
eyedeekay
6c62faa49b finish stubbing out noise transport stuff 2024-07-01 21:37:05 -04:00
eyedeekay
a7e31b7833 implement more noise stuff 2024-07-01 21:34:09 -04:00
eyedeekay
c09161c824 check in beginnings of new cleaned-up noise prototype 2024-07-01 18:50:13 -04:00
eyedeekay
aca62174e6 Load RI's into netDb struct for later referencing 2024-06-30 23:14:48 -04:00
eyedeekay
bd27f00959 add my unzip fork which fixes the permissions bug 2024-06-29 00:36:11 -04:00
eyedeekay
05c4d3d973 add my unzip fork which fixes the permissions bug 2024-06-29 00:25:23 -04:00
eyedeekay
40d0ea5ff5 Start making it so I can configure things, so I can configure it to read the netDb I already have and attempt to make a connection. Implement a reseed puller, or at least most of one. 2024-06-29 00:23:55 -04:00
eyedeekay
58e8f78c56 Start making it so I can configure things, so I can configure it to read the netDb I already have and attempt to make a connection. Implement a reseed puller, or at least most of one. 2024-06-29 00:23:42 -04:00
eyedeekay
ac705dee76 Set up a pre-release 2024-06-25 12:04:18 -04:00
eyedeekay
ca0443ae6a Set up a pre-release 2024-06-25 12:03:55 -04:00
eyedeekay
94d0d8efb7 Set up a pre-release 2024-06-25 12:03:09 -04:00
eyedeekay
8176e126cb Set up a pre-release 2024-06-25 12:02:49 -04:00
eyedeekay
992c5537db Set up a pre-release 2024-06-25 12:02:11 -04:00
eyedeekay
5ff9f5578e Update notes 2024-06-25 11:57:52 -04:00
eyedeekay
889ec939b3 Eliminate superfluous/rules-breaking logging 2024-06-25 11:41:55 -04:00
eyedeekay
6e3a5923cd Make MAX_GOOD_VERSION 99(0.9.99) 2024-06-25 09:35:39 -04:00
eyedeekay
ce25a2f0fb Add functions to examine caps 2024-06-24 22:26:17 -04:00
eyedeekay
ec22860bb5 Add Get function to MappingValues 2024-06-24 22:18:13 -04:00
eyedeekay
cefdcd8c14 RI parsing works again with options and caps and everything 2024-06-24 21:18:54 -04:00
eyedeekay
d519f7678d make logging clearer 2024-06-23 22:48:15 -04:00
eyedeekay
8dfc5ee5b8 Fix some string errors 2024-06-23 22:39:11 -04:00
eyedeekay
d8317351cf Write down my TODO thing 2024-06-23 03:41:40 -04:00
eyedeekay
ef127d81c1 Work on figuring out why the mapping size disagrees with the bytes 2024-06-23 03:24:57 -04:00
eyedeekay
8acfba160f Log some of the errors that came up after I fix the remainder emissions 2024-06-23 02:51:48 -04:00
eyedeekay
d93e78d772 Fix how it handles remainders of structures when parsing routerInfos 2024-06-23 01:35:42 -04:00
eyedeekay
bdc9ca4c2b Implement some missing ed25519 functions 2024-06-20 17:04:21 -04:00
eyedeekay
83f3d11621 Update the roadmap to more accurately reflect the actual state of the code 2024-02-09 15:02:46 -05:00
eyedeekay
784f72403b Fix padding, add TODO note, align spk to end of first 384 bytes 2024-02-05 12:41:49 -05:00
eyedeekay
664a17e42a Fix construction of keys_and_cert from a stream of bytes 2024-02-05 12:32:33 -05:00
eyedeekay
37718c36f8 Fix cert construction in keys_and_cert 2024-02-05 11:47:51 -05:00
eyedeekay
b0fcf4bc11 Fix mapping values, remove redundant, unused functions 2024-02-05 10:42:57 -05:00
159 changed files with 9865 additions and 954 deletions

2
.gitignore vendored
View File

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

View File

@@ -1,5 +1,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
ifdef GOROOT
GO = $(GOROOT)/bin/go
@@ -13,13 +16,61 @@ 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:
$(GO) test -v -failfast ./lib/transport/noise/...
test: check_gofumpt fmt
$(GO) test -v -failfast ./lib/common/...
clean:
$(GO) clean -v
fmt:
find . -name '*.go' -exec gofumpt -w {} \;
info:
echo "GOROOT: ${GOROOT}"
echo "GO: ${GO}"
echo "REPO: ${REPO}"
release:
github-release release -u go-i2p -r go-i2p -n "${RELEASE_VERSION}" -t "${RELEASE_TAG}" -d "${RELEASE_DESCRIPTION}" -p
callvis:
go-callvis -format svg -focus upgrade -group pkg,type -limit github.com/go-i2p/go-i2p github.com/go-i2p/go-i2p
godoc:
find lib -type d -exec bash -c "ls {}/*.go && godocdown -o ./{}/doc.md ./{}" \;
# Include test definitions
-include doc/tests/*.mk
# Define the all-tests target that runs every test suite
test-all: test-string-all \
test-mapping-all \
test-crypto-aes-all \
test-crypto-dsa-all \
test-crypto-ed25519-all \
test-crypto-elg-all \
test-crypto-hmac-all \
test-i2np-header-all \
test-i2np-build-request-all \
test-key-cert-all \
test-keys-cert-all \
test-lease-set-all \
test-noise-transport-all \
test-router-address-all \
test-router-info-all \
test-su3-all \
test-tunnel-all
#-include $(shell find doc/tests -type f -name '*.mk') #search for .mk files recursively
#test-base64-encode-decode-not-mangled:
#go test -v ./lib/common/base64 -run TestEncodeDecodeNotMangled

View File

@@ -1,16 +1,18 @@
Weekly notes about what I'm working on
======================================
At long last... something useful
================================
I finally got back to work on go-i2p last Friday, continuing work on the Noise transport(also enhanced marek's privs as a reddit mod which has been helpful, also the Dread community does appear to have begun to step a little re: onboarding eachother)
I can now make a socket, instantiate a noise transport using the socket, and begin to use it to manage "incoming" and "outgoing" handshakes.
They don't complete yet, still working on that, but it's more like debugging now and less figuring out how to actually do it, I more or less know where the pieces go now
I'm beginning to notice drawbacks of what I've done here already, I think noiseSocket is intended at times as example of a way to use flynn/noise which is not exactly like I would do it or how a P2P application needs to do it
Some of the functions are very long and hard to break down, and they use a different Noise flavor than NTCP2 by default, so I'm breaking things down into steps until I have exactly one step of a Noise handshake, exactly one function
Which should finally give me what I've been hoping for all along, an interface where I can modify steps(i.e. add padding, eventually turn it into NTCP2) by instantiating it with different versions of that function, so I get to think about reusability now
I'm going to attempt to ask a question I don't quite know how to ask yet, and maybe won't know the answer until I try it out for myself:
Supposing:
0. Go network structures can be "nested" if they implement the common interface(`net.Conn`, `net.PacketConn`), and use the common interface to store the information about the socket in their implmentation, and only use the functions of the common interface(This is true)
1. That I can instantiate this Noise-framework Transport struct with functions to modify the process in a granular enough way that turning it into NTCP2 is a matter of writing a few custom functions and plugging them in to an instance of the struct(Sort of like what you would do with inheritance)(which I think is true)
2. that I can instantiate it with both a `net.Conn(TCP Socket interface)` and a `net.PacketConn(UDP Socket interface)` because I only use the common features of those 2 interfaces, (Which isn't true yet but I'm thinking about how to do it)
Does that potential definition of a moddable Noise-over-many-transports library mean that I can approach SSU2 mostly in terms of connection management and peer testing, because the crypto would be similar enough to NTCP2 that I could re-use the custom functions?
I'll find out the hard way eventually the first time I have to do it with SSU2, but it would be exciting to have come up with a design that has accelerating returns in such a way.
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.

View File

@@ -41,7 +41,7 @@ please keep up with these changes, as they will not be backward compatible and r
- [ ] Elligator2
- [ ] HKDF
- [ ] HMAC
- [ ] Noise subsystem
- [/] Noise subsystem
- End-to-End Crypto
- [ ] Garlic messages
- [ ] ElGamal/AES+SessionTag
@@ -50,9 +50,9 @@ please keep up with these changes, as they will not be backward compatible and r
- [ ] Message parsing
- [ ] Message handling
- NetDB
- [ ] Local storage
- [ ] Persistence to disk
- [ ] Reseeding
- [/] Local storage
- [/] Persistence to disk
- [X] Reseeding
- [ ] Lookups
- [ ] Expiry
- [ ] Exploration
@@ -60,12 +60,12 @@ please keep up with these changes, as they will not be backward compatible and r
- [ ] Floodfill
- [ ] LS2 and Encrypted Leasesets
- Transports
- [ ] Transport manager
- [X] Transport manager
- NTCP2
- [ ] Handshake
- [ ] Session tracking
- [ ] Automatic session creation
- SSU
- SSU2
- [ ] Handshake
- [ ] Session tracking
- [ ] Automatic session creation
@@ -78,7 +78,40 @@ please keep up with these changes, as they will not be backward compatible and r
- [ ] Participating
- [ ] Tunnel Message Crypto
- [ ] Tunnel Message Fragmentation/Reassembly
- Common Data Structures
- [X] Keys and Cert
- [X] Key Certificates
- [X] Certificate
- [X] Lease
- [X] Lease Set
- [X] Router Info
- [X] Router Identity
- [X] Router Address
- [X] Session Key
- [X] Signature Types
- [X] Destination
- [X] Data Types
- [X] Session Tag
## Verbosity ##
Logging can be enabled and configured using the DEBUG_I2P environment variable. By default, logging is disabled.
There are three available log levels:
- Debug
```shell
export DEBUG_I2P=debug
```
- Warn
```shell
export DEBUG_I2P=warn
```
- Error
```shell
export DEBUG_I2P=error
```
If I2P_DEBUG is set to an unrecognized variable, it will fall back to "debug".
## Contributing

17
doc/tests/aes.mk Normal file
View File

@@ -0,0 +1,17 @@
test-crypto-aes-all: test-crypto-aes-core test-crypto-aes-validation test-crypto-aes-padding
test-crypto-aes-core:
go test -v ./lib/crypto -run TestAESEncryptDecrypt
test-crypto-aes-validation:
go test -v ./lib/crypto -run TestAESEncryptInvalidKey
go test -v ./lib/crypto -run TestAESDecryptInvalidInput
test-crypto-aes-padding:
go test -v ./lib/crypto -run TestPKCS7PadUnpad
go test -v ./lib/crypto -run TestPKCS7UnpadInvalidInput
.PHONY: test-crypto-aes-all \
test-crypto-aes-core \
test-crypto-aes-validation \
test-crypto-aes-padding

4
doc/tests/base32.mk Normal file
View File

@@ -0,0 +1,4 @@
test-base32-encode-decode-not-mangled:
go test -v ./lib/common/base32 -run TestEncodeDecodeNotMangled
.PHONY: test-base32-encode-decode-not-mangled

4
doc/tests/base64.mk Normal file
View File

@@ -0,0 +1,4 @@
test-base64-encode-decode-not-mangled:
go test -v ./lib/common/base64 -run TestEncodeDecodeNotMangled
.PHONY: test-base64-encode-decode-not-mangled

View File

@@ -0,0 +1,24 @@
test-build-request-all: test-build-request-receive test-build-request-ident test-build-request-components
test-build-request-receive:
go test -v ./lib/i2np -run TestReadBuildRequestRecordReceiveTunnel
test-build-request-ident:
go test -v ./lib/i2np -run TestReadBuildRequestRecordOurIdent
test-build-request-components:
go test -v ./lib/i2np -run TestReadBuildRequestRecordNextTunnel
go test -v ./lib/i2np -run TestReadBuildRequestRecordNextIdent
go test -v ./lib/i2np -run TestReadBuildRequestRecordLayerKey
go test -v ./lib/i2np -run TestReadBuildRequestRecordIVKey
go test -v ./lib/i2np -run TestReadBuildRequestRecordReplyKey
go test -v ./lib/i2np -run TestReadBuildRequestRecordReplyIV
go test -v ./lib/i2np -run TestReadBuildRequestRecordFlag
go test -v ./lib/i2np -run TestReadBuildRequestRecordRequestTime
go test -v ./lib/i2np -run TestReadBuildRequestRecordSendMessageID
go test -v ./lib/i2np -run TestReadBuildRequestRecordPadding
.PHONY: test-build-request-all \
test-build-request-receive \
test-build-request-ident \
test-build-request-components

61
doc/tests/certificate.mk Normal file
View File

@@ -0,0 +1,61 @@
test-cert-all: test-cert-type test-cert-length test-cert-data test-cert-read test-cert-length-correct test-cert-length-too-short test-cert-length-data-short test-cert-data-correct test-cert-data-too-long test-cert-data-too-short test-cert-read-correct test-cert-read-short test-cert-read-remainder test-cert-read-invalid
test-cert-type:
go test -v ./lib/common/certificate -run TestCertificateTypeIsFirstByte
test-cert-length:
go test -v ./lib/common/certificate -run TestCertificateLength
test-cert-data:
go test -v ./lib/common/certificate -run TestCertificateData
test-cert-read:
go test -v ./lib/common/certificate -run TestReadCertificate
test-cert-length-correct:
go test -v ./lib/common/certificate -run TestCertificateLengthCorrect
test-cert-length-too-short:
go test -v ./lib/common/certificate -run TestCertificateLengthErrWhenTooShort
test-cert-length-data-short:
go test -v ./lib/common/certificate -run TestCertificateLengthErrWhenDataTooShort
test-cert-data-correct:
go test -v ./lib/common/certificate -run TestCertificateDataWhenCorrectSize
test-cert-data-too-long:
go test -v ./lib/common/certificate -run TestCertificateDataWhenTooLong
test-cert-data-too-short:
go test -v ./lib/common/certificate -run TestCertificateDataWhenTooShort
test-cert-read-correct:
go test -v ./lib/common/certificate -run TestReadCertificateWithCorrectData
test-cert-read-short:
go test -v ./lib/common/certificate -run TestReadCertificateWithDataTooShort
test-cert-read-remainder:
go test -v ./lib/common/certificate -run TestReadCertificateWithRemainder
test-cert-read-invalid:
go test -v ./lib/common/certificate -run TestReadCertificateWithInvalidLength
# Declare all targets as PHONY
.PHONY: test-cert-all \
test-cert-type \
test-cert-length \
test-cert-data \
test-cert-read \
test-cert-length-correct \
test-cert-length-too-short \
test-cert-length-data-short \
test-cert-data-correct \
test-cert-data-too-long \
test-cert-data-too-short \
test-cert-read-correct \
test-cert-read-short \
test-cert-read-remainder \
test-cert-read-invalid

2
doc/tests/date.mk Normal file
View File

@@ -0,0 +1,2 @@
test-date-time-from-milliseconds:
go test -v ./lib/common/data -run TestTimeFromMilliseconds

20
doc/tests/dsa.mk Normal file
View File

@@ -0,0 +1,20 @@
test-crypto-dsa-all: test-crypto-dsa test-crypto-dsa-benchmarks
test-crypto-dsa:
go test -v ./lib/crypto -run TestDSA
test-crypto-dsa-benchmarks:
go test -v ./lib/crypto -bench=DSA -run=^$
# Individual benchmarks
test-crypto-dsa-bench-generate:
go test -v ./lib/crypto -bench=DSAGenerate -run=^$
test-crypto-dsa-bench-sign-verify:
go test -v ./lib/crypto -bench=DSASignVerify -run=^$
.PHONY: test-crypto-dsa-all \
test-crypto-dsa \
test-crypto-dsa-benchmarks \
test-crypto-dsa-bench-generate \
test-crypto-dsa-bench-sign-verify

7
doc/tests/ed25519.mk Normal file
View File

@@ -0,0 +1,7 @@
test-crypto-ed25519-all: test-crypto-ed25519
test-crypto-ed25519:
go test -v ./lib/crypto -run TestEd25519
.PHONY: test-crypto-ed25519-all \
test-crypto-ed25519

24
doc/tests/elg.mk Normal file
View File

@@ -0,0 +1,24 @@
test-crypto-elg-all: test-crypto-elg test-crypto-elg-benchmarks
test-crypto-elg:
go test -v ./lib/crypto -run TestElg
test-crypto-elg-benchmarks:
go test -v ./lib/crypto -bench=Elg -run=^$
# Individual benchmarks
test-crypto-elg-bench-generate:
go test -v ./lib/crypto -bench=ElgGenerate -run=^$
test-crypto-elg-bench-encrypt:
go test -v ./lib/crypto -bench=ElgEncrypt -run=^$
test-crypto-elg-bench-decrypt:
go test -v ./lib/crypto -bench=ElgDecrypt -run=^$
.PHONY: test-crypto-elg-all \
test-crypto-elg \
test-crypto-elg-benchmarks \
test-crypto-elg-bench-generate \
test-crypto-elg-bench-encrypt \
test-crypto-elg-bench-decrypt

30
doc/tests/header.mk Normal file
View File

@@ -0,0 +1,30 @@
test-i2np-header-all: test-i2np-type test-i2np-message test-i2np-expiration test-i2np-ntcp-components test-i2np-data test-i2np-regression
test-i2np-type:
go test -v ./lib/i2np -run TestReadI2NPTypeWith
test-i2np-message:
go test -v ./lib/i2np -run TestReadI2NPNTCPMessageID
test-i2np-expiration:
go test -v ./lib/i2np -run TestReadI2NPNTCPMessageExpiration
go test -v ./lib/i2np -run TestReadI2NPSSUMessageExpiration
test-i2np-ntcp-components:
go test -v ./lib/i2np -run TestReadI2NPNTCPMessageSize
go test -v ./lib/i2np -run TestReadI2NPNTCPMessageChecksum
test-i2np-data:
go test -v ./lib/i2np -run TestReadI2NPNTCPData
test-i2np-regression:
go test -v ./lib/i2np -run TestCrasherRegression123781
.PHONY: test-i2np-header-all \
test-i2np-type \
test-i2np-message \
test-i2np-expiration \
test-i2np-ntcp-components \
test-i2np-data \
test-i2np-regression

7
doc/tests/hmac.mk Normal file
View File

@@ -0,0 +1,7 @@
test-crypto-hmac-all: test-crypto-hmac
test-crypto-hmac:
go test -v ./lib/crypto -run Test_I2PHMAC
.PHONY: test-crypto-hmac-all \
test-crypto-hmac

15
doc/tests/integer.mk Normal file
View File

@@ -0,0 +1,15 @@
test-integer-all: test-integer-big-endian test-integer-one-byte test-integer-zero
test-integer-big-endian:
go test -v ./lib/common/integer -run TestIntegerBigEndian
test-integer-one-byte:
go test -v ./lib/common/integer -run TestWorksWithOneByte
test-integer-zero:
go test -v ./lib/common/integer -run TestIsZeroWithNoData
.PHONY: test-integer-all \
test-integer-big-endian \
test-integer-one-byte \
test-integer-zero

View File

@@ -0,0 +1,23 @@
test-key-cert-all: test-key-cert-signing test-key-cert-public test-key-cert-construct
test-key-cert-signing:
go test -v ./lib/common/key_certificate -run TestSingingPublicKeyTypeReturnsCorrectInteger
go test -v ./lib/common/key_certificate -run TestSingingPublicKeyTypeReportsWhenDataTooSmall
go test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyReportsWhenDataTooSmall
go test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithDSASHA1
go test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP256
go test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP384
go test -v ./lib/common/key_certificate -run TestConstructSigningPublicKeyWithP521
test-key-cert-public:
go test -v ./lib/common/key_certificate -run TestPublicKeyTypeReturnsCorrectInteger
go test -v ./lib/common/key_certificate -run TestPublicKeyTypeReportsWhenDataTooSmall
test-key-cert-construct:
go test -v ./lib/common/key_certificate -run TestConstructPublicKeyReportsWhenDataTooSmall
go test -v ./lib/common/key_certificate -run TestConstructPublicKeyReturnsCorrectDataWithElg
.PHONY: test-key-cert-all \
test-key-cert-signing \
test-key-cert-public \
test-key-cert-construct

View File

@@ -0,0 +1,30 @@
test-keys-cert-all: test-keys-cert-certificate test-keys-cert-public test-keys-cert-signing test-keys-cert-creation
test-keys-cert-certificate:
go test -v ./lib/common/keys_and_cert -run TestCertificateWithValidData
test-keys-cert-public:
go test -v ./lib/common/keys_and_cert -run TestPublicKeyWithBadData
go test -v ./lib/common/keys_and_cert -run TestPublicKeyWithBadCertificate
go test -v ./lib/common/keys_and_cert -run TestPublicKeyWithNullCertificate
go test -v ./lib/common/keys_and_cert -run TestPublicKeyWithKeyCertificate
test-keys-cert-signing:
go test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithBadData
go test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithBadCertificate
go test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithNullCertificate
go test -v ./lib/common/keys_and_cert -run TestSigningPublicKeyWithKeyCertificate
test-keys-cert-creation:
go test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithMissingData
go test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithMissingCertData
go test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithCertificate
go test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithoutCertificate
go test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithCertificateAndRemainder
go test -v ./lib/common/keys_and_cert -run TestNewKeysAndCertWithValidDataWithoutCertificateAndRemainder
.PHONY: test-keys-cert-all \
test-keys-cert-certificate \
test-keys-cert-public \
test-keys-cert-signing \
test-keys-cert-creation

22
doc/tests/lease_set.mk Normal file
View File

@@ -0,0 +1,22 @@
test-lease-set-all: test-lease-set-basic test-lease-set-leases test-lease-set-expiration
test-lease-set-basic:
go test -v ./lib/common/lease_set -run TestDestinationIsCorrect
go test -v ./lib/common/lease_set -run TestPublicKeyIsCorrect
go test -v ./lib/common/lease_set -run TestSigningKeyIsCorrect
go test -v ./lib/common/lease_set -run TestSignatureIsCorrect
test-lease-set-leases:
go test -v ./lib/common/lease_set -run TestLeaseCountCorrect
go test -v ./lib/common/lease_set -run TestLeaseCountCorrectWithMultiple
go test -v ./lib/common/lease_set -run TestLeaseCountErrorWithTooMany
go test -v ./lib/common/lease_set -run TestLeasesHaveCorrectData
test-lease-set-expiration:
go test -v ./lib/common/lease_set -run TestNewestExpirationIsCorrect
go test -v ./lib/common/lease_set -run TestOldestExpirationIsCorrect
.PHONY: test-lease-set-all \
test-lease-set-basic \
test-lease-set-leases \
test-lease-set-expiration

28
doc/tests/mapping.mk Normal file
View File

@@ -0,0 +1,28 @@
test-mapping-all: test-mapping-values test-mapping-duplicates test-mapping-conversion test-mapping-utils
test-mapping-values:
go test -v ./lib/common/data -run TestValuesExclusesPairWithBadData
go test -v ./lib/common/data -run TestValuesWarnsMissingData
go test -v ./lib/common/data -run TestValuesWarnsExtraData
go test -v ./lib/common/data -run TestValuesEnforcesEqualDelimitor
go test -v ./lib/common/data -run TestValuesEnforcedSemicolonDelimitor
go test -v ./lib/common/data -run TestValuesReturnsValues
test-mapping-duplicates:
go test -v ./lib/common/data -run TestHasDuplicateKeysTrueWhenDuplicates
go test -v ./lib/common/data -run TestHasDuplicateKeysFalseWithoutDuplicates
go test -v ./lib/common/data -run TestReadMappingHasDuplicateKeys
test-mapping-conversion:
go test -v ./lib/common/data -run TestGoMapToMappingProducesCorrectMapping
go test -v ./lib/common/data -run TestFullGoMapToMappingProducesCorrectMapping
test-mapping-utils:
go test -v ./lib/common/data -run TestStopValueRead
go test -v ./lib/common/data -run TestBeginsWith
.PHONY: test-mapping-all \
test-mapping-values \
test-mapping-duplicates \
test-mapping-conversion \
test-mapping-utils

View File

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

19
doc/tests/noise.mk Normal file
View 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

View File

@@ -0,0 +1,19 @@
test-router-address-all: test-router-address-validation test-router-address-functionality test-router-address-fuzz
test-router-address-validation:
go test -v ./lib/common/router_address -run TestCheckValidReportsEmptySlice
go test -v ./lib/common/router_address -run TestCheckRouterAddressValidReportsDataMissing
go test -v ./lib/common/router_address -run TestCheckRouterAddressValidNoErrWithValidData
test-router-address-functionality:
go test -v ./lib/common/router_address -run TestRouterAddressCostReturnsFirstByte
go test -v ./lib/common/router_address -run TestRouterAddressExpirationReturnsCorrectData
go test -v ./lib/common/router_address -run TestReadRouterAddressReturnsCorrectRemainderWithoutError
test-router-address-fuzz:
go test -v ./lib/common/router_address -run TestCorrectsFuzzCrasher1
.PHONY: test-router-address-all \
test-router-address-validation \
test-router-address-functionality \
test-router-address-fuzz

26
doc/tests/router_info.mk Normal file
View File

@@ -0,0 +1,26 @@
test-router-info-all: test-router-info-published test-router-info-addresses test-router-info-identity test-router-info-misc
test-router-info-published:
go test -v ./lib/common/router_info -run TestPublishedReturnsCorrectDate
go test -v ./lib/common/router_info -run TestPublishedReturnsCorrectErrorWithPartialDate
go test -v ./lib/common/router_info -run TestPublishedReturnsCorrectErrorWithInvalidData
test-router-info-addresses:
go test -v ./lib/common/router_info -run TestRouterAddressCountReturnsCorrectCount
go test -v ./lib/common/router_info -run TestRouterAddressCountReturnsCorrectErrorWithInvalidData
go test -v ./lib/common/router_info -run TestRouterAddressesReturnsAddresses
go test -v ./lib/common/router_info -run TestRouterAddressesReturnsAddressesWithMultiple
test-router-info-identity:
go test -v ./lib/common/router_info -run TestRouterIdentityIsCorrect
test-router-info-misc:
go test -v ./lib/common/router_info -run TestPeerSizeIsZero
go test -v ./lib/common/router_info -run TestOptionsAreCorrect
go test -v ./lib/common/router_info -run TestSignatureIsCorrectSize
.PHONY: test-router-info-all \
test-router-info-published \
test-router-info-addresses \
test-router-info-identity \
test-router-info-misc

27
doc/tests/string.mk Normal file
View File

@@ -0,0 +1,27 @@
test-string-all: test-string-length test-string-data test-string-conversion test-string-read
test-string-length:
go test -v ./lib/common/data -run TestStringReportsCorrectLength
go test -v ./lib/common/data -run TestI2PStringReportsLengthZeroError
go test -v ./lib/common/data -run TestI2PStringReportsExtraDataError
go test -v ./lib/common/data -run TestI2PStringDataReportsLengthZeroError
test-string-data:
go test -v ./lib/common/data -run TestI2PStringDataReportsExtraDataError
go test -v ./lib/common/data -run TestI2PStringDataEmptyWhenZeroLength
go test -v ./lib/common/data -run TestI2PStringDataErrorWhenNonZeroLengthOnly
test-string-conversion:
go test -v ./lib/common/data -run TestToI2PI2PStringFormatsCorrectly
go test -v ./lib/common/data -run TestToI2PStringReportsOverflows
test-string-read:
go test -v ./lib/common/data -run TestReadStringReadsLength
go test -v ./lib/common/data -run TestReadI2PStringErrWhenEmptySlice
go test -v ./lib/common/data -run TestReadI2PStringErrWhenDataTooShort
.PHONY: test-string-all \
test-string-length \
test-string-data \
test-string-conversion \
test-string-read

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

@@ -0,0 +1,11 @@
test-su3-all: test-su3-read test-su3-signature
test-su3-read:
go test -v ./lib/su3 -run TestRead
test-su3-signature:
go test -v ./lib/su3 -run TestReadSignatureFirst
.PHONY: test-su3-all \
test-su3-read \
test-su3-signature

22
doc/tests/tunnel.mk Normal file
View File

@@ -0,0 +1,22 @@
test-tunnel-all: test-tunnel-delivery-instructions test-tunnel-message
# Tests from delivery_test.go
test-tunnel-delivery-instructions:
go test -v ./lib/tunnel -run TestReadDeliveryInstructions
# Tests from message_test.go
test-tunnel-message: test-tunnel-message-padding test-tunnel-message-fragments
test-tunnel-message-padding:
go test -v ./lib/tunnel -run TestDeliveryInstructionDataWithNoPadding
go test -v ./lib/tunnel -run TestDeliveryInstructionDataWithSomePadding
go test -v ./lib/tunnel -run TestDeliveryInstructionDataWithOnlyPadding
test-tunnel-message-fragments:
go test -v ./lib/tunnel -run TestDeliveryInstructionsWithFragments
.PHONY: test-tunnel-all \
test-tunnel-delivery-instructions \
test-tunnel-message \
test-tunnel-message-padding \
test-tunnel-message-fragments

49
go.mod
View File

@@ -1,15 +1,46 @@
module github.com/go-i2p/go-i2p
go 1.16
go 1.23.1
require (
github.com/dchest/siphash v1.2.3 // indirect
github.com/emirpasic/gods v1.18.1
github.com/flynn/noise v1.0.0
github.com/go-noisesocket/noisesocket v0.0.0-20191014121341-f487ac765620
github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.9.0
github.com/stretchr/testify v1.7.0
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
github.com/beevik/ntp v1.4.3
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e
github.com/flynn/noise v1.1.0
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
go.step.sm/crypto v0.53.0
golang.org/x/crypto v0.27.0
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.19.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sys v0.24.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

95
go.sum
View File

@@ -1,45 +1,100 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho=
github.com/beevik/ntp v1.4.3/go.mod h1:Unr8Zg+2dRn7d8bHFuehIMSvvUYssHMxW3Q5Nx4RW5Q=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA=
github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc=
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/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ=
github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
github.com/go-noisesocket/noisesocket v0.0.0-20191014121341-f487ac765620 h1:MjTFQi2DyJifqefRVjAs+P2gaoUAj2rcDpYX7ERggEA=
github.com/go-noisesocket/noisesocket v0.0.0-20191014121341-f487ac765620/go.mod h1:y9SBFk2hEIPWY7Aj3bXG+K1xp8wWnQ6kVq2wsYSPByU=
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e h1:NMjWYVkgcQHGOy0/VxU0TU6smrcoxzj9hwDesx2sB0w=
github.com/eyedeekay/go-unzip v0.0.0-20240201194209-560d8225b50e/go.mod h1:fKfFM3BsOOyjtZmEty7FsGzGabXo8Eb/dHjyIhTtxsE=
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/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/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-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
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-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/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=

View File

@@ -1,4 +1,2 @@
//
// provides generic interfaces for initial bootstrap into network and network reseeding
//
package bootstrap

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

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

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

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

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

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

View File

@@ -5,11 +5,16 @@ package certificate
import (
"fmt"
log "github.com/sirupsen/logrus"
"github.com/sirupsen/logrus"
// log "github.com/sirupsen/logrus"
"github.com/go-i2p/go-i2p/lib/util/logger"
. "github.com/go-i2p/go-i2p/lib/common/data"
)
var log = logger.GetGoI2PLogger()
// Certificate Types
const (
CERT_NULL = iota
@@ -70,12 +75,23 @@ func (c *Certificate) RawBytes() []byte {
bytes := c.kind.Bytes()
bytes = append(bytes, c.len.Bytes()...)
bytes = append(bytes, c.payload...)
log.WithFields(logrus.Fields{
"raw_bytes_length": len(bytes),
}).Debug("Generated raw bytes for certificate")
return bytes
}
// ExcessBytes returns the excess bytes in a certificate found after the specified payload length.
func (c *Certificate) ExcessBytes() []byte {
return c.payload[c.len.Int():]
if len(c.payload) >= c.len.Int() {
excess := c.payload[c.len.Int():]
log.WithFields(logrus.Fields{
"excess_bytes_length": len(excess),
}).Debug("Found excess bytes in certificate")
return excess
}
log.Debug("No excess bytes found in certificate")
return nil
}
// Bytes returns the entire certificate in []byte form, trims payload to specified length.
@@ -83,6 +99,9 @@ func (c *Certificate) Bytes() []byte {
bytes := c.kind.Bytes()
bytes = append(bytes, c.len.Bytes()...)
bytes = append(bytes, c.Data()...)
log.WithFields(logrus.Fields{
"bytes_length": len(bytes),
}).Debug("Generated bytes for certificate")
return bytes
}
@@ -94,12 +113,18 @@ func (c *Certificate) length() (cert_len int) {
// Type returns the Certificate type specified in the first byte of the Certificate,
func (c *Certificate) Type() (cert_type int) {
cert_type = c.kind.Int()
log.WithFields(logrus.Fields{
"cert_type": cert_type,
}).Debug("Retrieved certificate type")
return
}
// Length returns the payload length of a Certificate.
func (c *Certificate) Length() (length int) {
length = c.len.Int()
log.WithFields(logrus.Fields{
"length": length,
}).Debug("Retrieved certificate length")
return
}
@@ -108,47 +133,41 @@ func (c *Certificate) Data() (data []byte) {
lastElement := c.Length()
if lastElement > len(c.payload) {
data = c.payload
log.Warn("Certificate payload shorter than specified length")
} else {
data = c.payload[0:lastElement]
}
log.WithFields(logrus.Fields{
"data_length": len(data),
}).Debug("Retrieved certificate data")
return
}
// NewCertificate creates a new Certficiate from []byte
// returns err if the certificate is too short or if the payload doesn't match specified length.
func NewCertificate(data []byte) (certificate *Certificate, err error) {
certificate = &Certificate{}
func NewCertificate(data []byte) (certificate Certificate, err error) {
certificate = Certificate{}
switch len(data) {
case 0:
certificate.kind = Integer([]byte{0})
certificate.len = Integer([]byte{0})
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": len(data),
"reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()),
}).Error("invalid certificate")
err = fmt.Errorf("error parsing certificate: certificate is too short")
}).Error("invalid certificate, empty")
err = fmt.Errorf("error parsing certificate: certificate is empty")
return
case 1:
certificate.kind = Integer(data[0:0])
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()),
}).Error("invalid certificate")
}).Error("invalid certificate, too short")
err = fmt.Errorf("error parsing certificate: certificate is too short")
return
case 2:
certificate.kind = Integer(data[0:1])
certificate.len = Integer([]byte{0})
log.WithFields(log.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")
err = fmt.Errorf("error parsing certificate length: certificate is too short")
return
default:
certificate.kind = Integer(data[0:1])
certificate.len = Integer(data[1:3])
@@ -156,34 +175,36 @@ func NewCertificate(data []byte) (certificate *Certificate, err error) {
certificate.payload = data[CERT_MIN_SIZE:]
if certificate.len.Int() > len(data)-CERT_MIN_SIZE {
err = fmt.Errorf("certificate parsing warning: certificate data is shorter than specified by length")
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": certificate.len.Int(),
"certificate_payload_length": payleng,
"data_bytes:": string(data),
"kind_bytes": data[0:1],
"len_bytes": data[1:3],
"reason": err.Error(),
}).Error("invalid certificate")
return
} else if certificate.len.Int() < len(data)-CERT_MIN_SIZE {
err = fmt.Errorf("certificate parsing warning: certificate data is longer than specified by length")
log.WithFields(log.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": certificate.len.Int(),
"certificate_payload_length": payleng,
"reason": err.Error(),
}).Error("invalid certificate")
}).Error("invalid certificate, shorter than specified by length")
return
}
log.WithFields(logrus.Fields{
"type": certificate.kind.Int(),
"length": certificate.len.Int(),
}).Debug("Successfully created new certificate")
return
}
}
// ReadCertificate creates a Certificate from []byte and returns any ExcessBytes at the end of the input.
// returns err if the certificate could not be read.
func ReadCertificate(data []byte) (certificate *Certificate, remainder []byte, err error) {
func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, err error) {
certificate, err = NewCertificate(data)
if err != nil && err.Error() == "certificate parsing warning: certificate data is longer than specified by length" {
remainder = certificate.ExcessBytes()
log.Warn("Certificate data longer than specified length")
err = nil
}
remainder = certificate.ExcessBytes()
log.WithFields(logrus.Fields{
"remainder_length": len(remainder),
}).Debug("Read certificate and extracted remainder")
return
}

View File

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

View File

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

View File

@@ -5,9 +5,12 @@ import (
"errors"
"time"
log "github.com/sirupsen/logrus"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
)
var log = logger.GetGoI2PLogger()
// DATE_SIZE is the length in bytes of an I2P Date.
const DATE_SIZE = 8
@@ -51,7 +54,7 @@ func (date Date) Time() (date_time time.Time) {
// Any data after DATE_SIZE is returned as a remainder.
func ReadDate(data []byte) (date Date, remainder []byte, err error) {
if len(data) < 8 {
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"data": data,
}).Error("ReadDate: data is too short")
err = errors.New("ReadDate: data is too short")
@@ -59,6 +62,10 @@ func ReadDate(data []byte) (date Date, remainder []byte, err error) {
}
copy(date[:], data[:8])
remainder = data[8:]
log.WithFields(logrus.Fields{
"date_value": date.Int(),
"remainder_length": len(remainder),
}).Debug("Successfully read Date from data")
return
}
@@ -66,6 +73,15 @@ func ReadDate(data []byte) (date Date, remainder []byte, err error) {
// Returns a pointer to Date unlike ReadDate.
func NewDate(data []byte) (date *Date, remainder []byte, err error) {
objdate, remainder, err := ReadDate(data)
if err != nil {
log.WithError(err).Error("Failed to create new Date")
return nil, remainder, err
}
date = &objdate
log.WithFields(logrus.Fields{
"date_value": date.Int(),
"remainder_length": len(remainder),
}).Debug("Successfully created new Date")
return
}

View File

@@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/assert"
)
func TestTimeFromMiliseconds(t *testing.T) {
func TestTimeFromMilliseconds(t *testing.T) {
assert := assert.New(t)
next_day := Date{0x00, 0x00, 0x00, 0x00, 0x05, 0x26, 0x5c, 0x00}

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

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

View File

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

View File

@@ -50,7 +50,9 @@ func NewInteger(bytes []byte, size int) (integer *Integer, remainder []byte, err
if size < MAX_INTEGER_SIZE {
integerSize = size
}
i, remainder := ReadInteger(bytes, integerSize)
intBytes := bytes[:integerSize]
remainder = bytes[integerSize:]
i, _ := ReadInteger(intBytes, integerSize)
integer = &i
return
}

View File

@@ -3,7 +3,7 @@ package data
import (
"errors"
log "github.com/sirupsen/logrus"
"github.com/sirupsen/logrus"
)
/*
@@ -48,8 +48,12 @@ type Mapping struct {
// Values returns the values contained in a Mapping as MappingValues.
func (mapping Mapping) Values() MappingValues {
if mapping.vals == nil {
log.Debug("Mapping values are nil, returning empty MappingValues")
return MappingValues{}
}
log.WithFields(logrus.Fields{
"values_count": len(*mapping.vals),
}).Debug("Retrieved Mapping values")
return *mapping.vals
}
@@ -74,30 +78,40 @@ func (mapping *Mapping) Data() []byte {
// HasDuplicateKeys returns true if two keys in a mapping are identical.
func (mapping *Mapping) HasDuplicateKeys() bool {
log.Debug("Checking for duplicate keys in Mapping")
seen_values := make(map[string]bool)
values := mapping.Values()
for _, pair := range values {
key, _ := pair[0].Data()
if _, present := seen_values[key]; present {
log.WithFields(logrus.Fields{
"duplicate_key": key,
}).Warn("Found duplicate key in Mapping")
return true
} else {
seen_values[key] = true
}
}
log.Debug("No duplicate keys found in Mapping")
return false
}
// GoMapToMapping converts a Go map of unformatted strings to *Mapping.
func GoMapToMapping(gomap map[string]string) (mapping *Mapping, err error) {
log.WithFields(logrus.Fields{
"input_map_size": len(gomap),
}).Debug("Converting Go map to Mapping")
map_vals := MappingValues{}
for k, v := range gomap {
key_str, kerr := ToI2PString(k)
if kerr != nil {
log.WithError(kerr).Error("Failed to convert key to I2PString")
err = kerr
return
}
val_str, verr := ToI2PString(v)
if verr != nil {
log.WithError(verr).Error("Failed to convert value to I2PString")
err = verr
return
}
@@ -107,74 +121,113 @@ 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) {
if len(bytes) == 0 {
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"input_length": len(bytes),
}).Debug("Reading Mapping from bytes")
if len(bytes) < 3 {
log.WithFields(logrus.Fields{
"at": "ReadMapping",
"reason": "zero length",
}).Warn("mapping format violation")
e := errors.New("zero length")
err = append(err, e)
return
}
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
if e != nil {
log.WithFields(log.Fields{
"at": "ReadMapping",
"reason": "error parsing integer",
}).Warn("mapping format violation")
e := errors.New("error parsing integer")
err = append(err, e)
}
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")
e := errors.New("zero length")
err = append(err, e)
}
vals, remainder, mappingValueErrs := ReadMappingValues(bytes)
// TODO: this should take the remainder and the length we already parsed above, as a parameter.
// Like tomorrow morning.
// ReadMappingValues should not attempt to figure out the length of the bytes it's reading over.
vals, _, mappingValueErrs := ReadMappingValues(map_bytes, *mapping.size)
err = append(err, mappingValueErrs...)
mapping.vals = vals
if len(mappingValueErrs) > 0 {
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "ReadMapping",
"reason": "error parsing mapping values",
}).Warn("mapping format violation")
e := errors.New("error parsing mapping values")
err = append(err, e)
}
log.WithFields(logrus.Fields{
"mapping_size": mapping.size.Int(),
"values_count": len(*mapping.vals),
"remainder_length": len(remainder),
"error_count": len(err),
}).Debug("Finished reading Mapping")
return
}
// NewMapping creates a new *Mapping from []byte using ReadMapping.
// Returns a pointer to Mapping unlike ReadMapping.
func NewMapping(bytes []byte) (values *Mapping, remainder []byte, err []error) {
log.WithFields(logrus.Fields{
"input_length": len(bytes),
}).Debug("Creating new Mapping")
objvalues, remainder, err := ReadMapping(bytes)
values = &objvalues
log.WithFields(logrus.Fields{
"values_count": len(values.Values()),
"remainder_length": len(remainder),
"error_count": len(err),
}).Debug("Finished creating new Mapping")
return
}

View File

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

View File

@@ -4,18 +4,42 @@ import (
"errors"
"sort"
log "github.com/sirupsen/logrus"
"github.com/sirupsen/logrus"
)
// MappingValues represents the parsed key value pairs inside of an I2P Mapping.
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 {
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
}
// ValuesToMapping creates a *Mapping using MappingValues.
// The values are sorted in the order defined in mappingOrder.
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 {
@@ -23,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,
@@ -46,12 +74,17 @@ func mappingOrder(values MappingValues) {
// 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 ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes []byte, errs []error) {
mapping := remainder
//var remainder = mapping
//var err error
if remainder == nil || len(remainder) < 0 {
log.WithFields(log.Fields{
func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingValues, remainder_bytes []byte, errs []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(logrus.Fields{
"at": "(Mapping) Values",
"reason": "data shorter than expected",
}).Error("mapping contained no data")
@@ -59,31 +92,21 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
return
}
map_values := make(MappingValues, 0)
if len(remainder) < 1 {
log.WithFields(log.Fields{
"at": "(Mapping) Values",
"reason": "data shorter than expected",
}).Error("mapping contained no data")
errs = []error{errors.New("mapping contained no data")}
return
}
l := Integer(remainder[:2])
length := l.Int()
// - 2 bytes for map length bits
mapping_len := len(mapping) - 2
if mapping_len > length {
log.WithFields(log.Fields{
int_map_length := map_length.Int()
mapping_len := len(remainder)
if mapping_len > int_map_length {
log.WithFields(logrus.Fields{
"at": "(Mapping) Values",
"mapping_bytes_length": mapping_len,
"mapping_length_field": length,
"mapping_length_field": int_map_length,
"reason": "data longer than expected",
}).Warn("mapping format warning")
errs = append(errs, errors.New("warning parsing mapping: data exists beyond length of mapping"))
} else if length > mapping_len {
log.WithFields(log.Fields{
} else if int_map_length > mapping_len {
log.WithFields(logrus.Fields{
"at": "(Mapping) Values",
"mapping_bytes_length": mapping_len,
"mapping_length_field": length,
"mapping_length_field": int_map_length,
"reason": "data shorter than expected",
}).Warn("mapping format warning")
errs = append(errs, errors.New("warning parsing mapping: mapping length exceeds provided data"))
@@ -91,7 +114,7 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
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
@@ -104,33 +127,35 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
// 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")
break
}
str, more, err := ReadI2PString(remainder)
// overwriting remainder with more as another var to prevent memory weirdness in loops
remainder = more
key_str := str
key_str, more, err := ReadI2PString(remainder)
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)
// 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)
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.
@@ -139,36 +164,42 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
}
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)
break
} else {
remainder = remainder[1:]
}
remainder = remainder[1:]
// Read a value, breaking on fatal errors
// and appending warnings
str, more, err = ReadI2PString(remainder)
// overwriting remainder with more as another var to prevent memory weirdness in loops
remainder = more
val_str := str
val_str, more, err := ReadI2PString(remainder)
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)
if !beginsWith(remainder, 0x3b) {
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 ;"))
break
} else {
remainder = remainder[1:]
}
remainder = remainder[1:]
// Append the key-value pair and break if there is no more data to read
map_values = append(map_values, [2]I2PString{key_str, val_str})
@@ -180,6 +211,12 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
encounteredKeysMap[keyAsString] = true
}
values = &map_values
return
log.WithFields(logrus.Fields{
"values_count": len(map_values),
"remainder_length": len(remainder_bytes),
"error_count": len(errs),
}).Debug("Finished reading MappingValues")
return
}

View File

@@ -2,8 +2,9 @@ package data
import (
"errors"
"fmt"
log "github.com/sirupsen/logrus"
"github.com/sirupsen/logrus"
)
// STRING_MAX_SIZE is the maximum number of bytes that can be stored in an I2P string
@@ -31,35 +32,35 @@ 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 := Integer([]byte{byte(str[0])})
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()
inferred_len := length + 1
str_len := len(str)
if inferred_len > str_len {
log.WithFields(log.Fields{
"at": "(I2PString) Length",
"string_bytes_length": str_len,
"string_length_field": length,
"expected_bytes_length": inferred_len,
"reason": "data shorter than specified",
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",
}).Warn("string format warning")
err = errors.New("string parsing warning: string data is shorter than specified by length")
} else if str_len > inferred_len {
log.WithFields(log.Fields{
"at": "(I2PString) Length",
"string_bytes_length": str_len,
"string_length_field": length,
"expected_bytes_length": inferred_len,
"reason": "data longer than specified",
}).Warn("string format warning")
err = errors.New("string parsing warning: string contains data beyond length")
}
return
}
@@ -71,25 +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":
data = string(str[1 : length+1])
log.WithError(err).Warn("I2PString contains data beyond specified length")
data = string(str[1:])
return
}
}
data = string(str[1:])
if length == 0 {
log.Debug("I2PString is empty")
return
}
data = string(str[1 : length+1])
log.WithFields(logrus.Fields{
"data_length": len(data),
}).Debug("Retrieved I2PString data")
return
}
// ToI2PString converts a Go string to an I2PString.
// Returns error if the string exceeds STRING_MAX_SIZE.
func ToI2PString(data string) (str I2PString, err error) {
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Converting string to I2PString")
data_len := len(data)
if data_len > STRING_MAX_SIZE {
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "ToI2PI2PString",
"string_len": data_len,
"max_len": STRING_MAX_SIZE,
@@ -101,6 +119,9 @@ func ToI2PString(data string) (str I2PString, err error) {
i2p_string := []byte{byte(data_len)}
i2p_string = append(i2p_string, []byte(data)...)
str = I2PString(i2p_string)
log.WithFields(logrus.Fields{
"i2pstring_length": len(str),
}).Debug("Successfully converted string to I2PString")
return
}
@@ -113,20 +134,37 @@ func ToI2PString(data string) (str I2PString, err error) {
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadI2PString(data []byte) (str I2PString, remainder []byte, err error) {
str = I2PString(data)
length, err := I2PString(data).Length()
if err != nil && err.Error() == "string parsing warning: string contains data beyond length" {
str = I2PString(data[:length+1])
remainder = data[length+1:]
err = nil
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
str = data[:data_len]
remainder = data[data_len:]
l, err := str.Length()
if l != data_len-1 {
err = fmt.Errorf("error reading I2P string, length does not match data")
log.WithFields(logrus.Fields{
"expected_length": data_len - 1,
"actual_length": l,
}).Error("I2PString length mismatch")
return
}
log.WithFields(logrus.Fields{
"string_length": l,
"remainder_length": len(remainder),
}).Debug("Successfully read I2PString from bytes")
return
}
// NewI2PString creates a new *I2PString from []byte using ReadI2PString.
// Returns a pointer to I2PString unlike ReadI2PString.
func NewI2PString(data []byte) (str *I2PString, remainder []byte, err error) {
/*func NewI2PString(data []byte) (str *I2PString, remainder []byte, err error) {
objstr, remainder, err := ReadI2PString(data)
str = &objstr
return
}
}*/

View File

@@ -4,6 +4,9 @@ package destination
import (
"strings"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
. "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
"github.com/go-i2p/go-i2p/lib/common/base32"
@@ -11,6 +14,8 @@ import (
"github.com/go-i2p/go-i2p/lib/crypto"
)
var log = logger.GetGoI2PLogger()
/*
[Destination]
Accurate for version 0.9.49
@@ -26,39 +31,55 @@ Identical to KeysAndCert.
//
// https://geti2p.net/spec/common-structures#destination
type Destination struct {
*KeysAndCert
KeysAndCert
}
// Base32Address returns the I2P base32 address for this Destination.
func (destination Destination) Base32Address() (str string) {
log.Debug("Generating Base32 address for Destination")
dest := destination.KeysAndCert.KeyCertificate.Bytes()
hash := crypto.SHA256(dest)
str = strings.Trim(base32.EncodeToString(hash[:]), "=")
str = str + ".b32.i2p"
log.WithFields(logrus.Fields{
"base32_address": str,
}).Debug("Generated Base32 address for Destination")
return
}
// Base64 returns the I2P base64 address for this Destination.
func (destination Destination) Base64() string {
log.Debug("Generating Base64 address for Destination")
dest := destination.KeysAndCert.KeyCertificate.Bytes()
return base64.EncodeToString(dest)
base64Address := base64.EncodeToString(dest)
log.WithFields(logrus.Fields{
"base64_address_length": len(base64Address),
}).Debug("Generated Base64 address for Destination")
return base64Address
}
// ReadDestination returns Destination from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadDestination(data []byte) (destination Destination, remainder []byte, err error) {
keys_and_cert, remainder, err := NewKeysAndCert(data)
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Reading Destination from bytes")
keys_and_cert, remainder, err := ReadKeysAndCert(data)
destination = Destination{
keys_and_cert,
}
log.WithFields(logrus.Fields{
"remainder_length": len(remainder),
}).Debug("Successfully read Destination from bytes")
return
}
// NewDestination creates a new *Destination from []byte using ReadDestination.
// Returns a pointer to Destination unlike ReadDestination.
func NewDestination(data []byte) (destination *Destination, remainder []byte, err error) {
objdestination, remainder, err := ReadDestination(data)
destination = &objdestination
return destination, remainder, err
}

View File

@@ -0,0 +1,42 @@
# destination
--
import "github.com/go-i2p/go-i2p/lib/common/destination"
Package destination implements the I2P Destination common data structure
## Usage
#### type Destination
```go
type Destination struct {
KeysAndCert
}
```
Destination is the represenation of an I2P Destination.
https://geti2p.net/spec/common-structures#destination
#### func ReadDestination
```go
func ReadDestination(data []byte) (destination Destination, remainder []byte, err error)
```
ReadDestination returns Destination from a []byte. The remaining bytes after the
specified length are also returned. Returns a list of errors that occurred
during parsing.
#### func (Destination) Base32Address
```go
func (destination Destination) Base32Address() (str string)
```
Base32Address returns the I2P base32 address for this Destination.
#### func (Destination) Base64
```go
func (destination Destination) Base64() string
```
Base64 returns the I2P base64 address for this Destination.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -30,12 +30,16 @@ payload :: data
import (
"errors"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
. "github.com/go-i2p/go-i2p/lib/common/certificate"
. "github.com/go-i2p/go-i2p/lib/common/data"
"github.com/go-i2p/go-i2p/lib/crypto"
log "github.com/sirupsen/logrus"
)
var log = logger.GetGoI2PLogger()
// Key Certificate Signing Key Types
const (
KEYCERT_SIGN_DSA_SHA1 = iota
@@ -52,6 +56,10 @@ const (
// Key Certificate Public Key Types
const (
KEYCERT_CRYPTO_ELG = iota
KEYCERT_CRYPTO_P256
KEYCERT_CRYPTO_P384
KEYCERT_CRYPTO_P521
KEYCERT_CRYPTO_X25519
)
const (
@@ -73,7 +81,11 @@ const (
// PublicKey sizes for Public Key Types
const (
KEYCERT_CRYPTO_ELG_SIZE = 256
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
)
// Sizes of structures in KeyCertificates
@@ -82,38 +94,53 @@ const (
KEYCERT_SPK_SIZE = 128
)
//type KeyCertificate []byte
// type KeyCertificate []byte
type KeyCertificate struct {
*Certificate
Certificate
spkType Integer
cpkType Integer
}
// Data returns the raw []byte contained in the Certificate.
func (key_certificate KeyCertificate) Data() ([]byte, error) {
data := key_certificate.Certificate.RawBytes()
log.WithFields(logrus.Fields{
"data_length": len(data),
}).Debug("Retrieved raw data from KeyCertificate")
return key_certificate.Certificate.RawBytes(), nil
}
// SigningPublicKeyType returns the SigningPublicKey type as a Go integer.
func (key_certificate KeyCertificate) SigningPublicKeyType() (signing_pubkey_type int) {
signing_pubkey_type = key_certificate.spkType.Int()
log.WithFields(logrus.Fields{
"signing_pubkey_type": signing_pubkey_type,
}).Debug("Retrieved SigningPublicKey type")
return key_certificate.spkType.Int()
}
// PublicKeyType returns the PublicKey type as a Go integer.
func (key_certificate KeyCertificate) PublicKeyType() (pubkey_type int) {
pubkey_type = key_certificate.cpkType.Int()
log.WithFields(logrus.Fields{
"pubkey_type": pubkey_type,
}).Debug("Retrieved PublicKey type")
return key_certificate.cpkType.Int()
}
// ConstructPublicKey returns a PublicKey constructed using any excess data that may be stored in the KeyCertififcate.
// Returns enr errors encountered while parsing.
func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_key crypto.PublicKey, err error) {
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Constructing PublicKey from KeyCertificate")
key_type := key_certificate.PublicKeyType()
if err != nil {
return
}
data_len := len(data)
if data_len < KEYCERT_PUBKEY_SIZE {
log.WithFields(log.Fields{
if data_len < key_certificate.CryptoSize() {
log.WithFields(logrus.Fields{
"at": "(KeyCertificate) ConstructPublicKey",
"data_len": data_len,
"required_len": KEYCERT_PUBKEY_SIZE,
@@ -127,20 +154,34 @@ func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_ke
var elg_key crypto.ElgPublicKey
copy(elg_key[:], data[KEYCERT_PUBKEY_SIZE-KEYCERT_CRYPTO_ELG_SIZE:KEYCERT_PUBKEY_SIZE])
public_key = elg_key
log.Debug("Constructed ElgPublicKey")
case KEYCERT_CRYPTO_X25519:
var ed25519_key crypto.Ed25519PublicKey
copy(ed25519_key[:], data[KEYCERT_PUBKEY_SIZE-KEYCERT_CRYPTO_ELG_SIZE:KEYCERT_PUBKEY_SIZE])
public_key = ed25519_key
log.Debug("Constructed Ed25519PublicKey")
default:
log.WithFields(logrus.Fields{
"key_type": key_type,
}).Warn("Unknown public key type")
}
return
}
// ConstructSigningPublicKey returns a SingingPublicKey constructed using any excess data that may be stored in the KeyCertificate.
// Returns any errors encountered while parsing.
func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (signing_public_key crypto.SigningPublicKey, err error) {
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Constructing SigningPublicKey from KeyCertificate")
signing_key_type := key_certificate.PublicKeyType()
if err != nil {
return
}
data_len := len(data)
if data_len < KEYCERT_SPK_SIZE {
log.WithFields(log.Fields{
if data_len < key_certificate.SignatureSize() {
log.WithFields(logrus.Fields{
"at": "(KeyCertificate) ConstructSigningPublicKey",
"data_len": data_len,
"required_len": KEYCERT_SPK_SIZE,
@@ -154,48 +195,95 @@ func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (si
var dsa_key crypto.DSAPublicKey
copy(dsa_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_DSA_SHA1_SIZE:KEYCERT_SPK_SIZE])
signing_public_key = dsa_key
log.Debug("Constructed DSAPublicKey")
case KEYCERT_SIGN_P256:
var ec_key crypto.ECP256PublicKey
copy(ec_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_P256_SIZE:KEYCERT_SPK_SIZE])
signing_public_key = ec_key
log.Debug("Constructed ECP256PublicKey")
case KEYCERT_SIGN_P384:
var ec_key crypto.ECP384PublicKey
copy(ec_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_P384_SIZE:KEYCERT_SPK_SIZE])
signing_public_key = ec_key
log.Debug("Constructed ECP384PublicKey")
case KEYCERT_SIGN_P521:
var ec_key crypto.ECP521PublicKey
extra := KEYCERT_SIGN_P521_SIZE - KEYCERT_SPK_SIZE
copy(ec_key[:], data)
copy(ec_key[KEYCERT_SPK_SIZE:], key_certificate.Certificate.RawBytes()[4:4+extra])
signing_public_key = ec_key
log.Debug("Constructed ECP521PublicKey")
case KEYCERT_SIGN_RSA2048:
//var rsa_key crypto.RSA2048PublicKey
//extra := KEYCERT_SIGN_RSA2048_SIZE - 128
//copy(rsa_key[:], data)
//copy(rsa_key[128:], key_certificate[4:4+extra])
//signing_public_key = rsa_key
// var rsa_key crypto.RSA2048PublicKey
// extra := KEYCERT_SIGN_RSA2048_SIZE - 128
// copy(rsa_key[:], data)
// copy(rsa_key[128:], key_certificate[4:4+extra])
// signing_public_key = rsa_key
log.WithFields(logrus.Fields{
"signing_key_type": signing_key_type,
}).Warn("Signing key type KEYCERT_SIGN_RSA2048 not implemented")
case KEYCERT_SIGN_RSA3072:
log.WithFields(logrus.Fields{
"signing_key_type": signing_key_type,
}).Warn("Signing key type KEYCERT_SIGN_RSA3072 not implemented")
case KEYCERT_SIGN_RSA4096:
log.WithFields(logrus.Fields{
"signing_key_type": signing_key_type,
}).Warn("Signing key type KEYCERT_SIGN_RSA4096 not implemented")
case KEYCERT_SIGN_ED25519:
log.WithFields(logrus.Fields{
"signing_key_type": signing_key_type,
}).Warn("Signing key type KEYCERT_SIGN_ED25519 not implemented")
case KEYCERT_SIGN_ED25519PH:
log.WithFields(logrus.Fields{
"signing_key_type": signing_key_type,
}).Warn("Signing key type KEYCERT_SIGN_ED25519PH not implemented")
default:
log.WithFields(logrus.Fields{
"signing_key_type": signing_key_type,
}).Warn("Unknown signing key type")
}
return
}
// 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: 40,
KEYCERT_SIGN_P256: 64,
KEYCERT_SIGN_P384: 96,
KEYCERT_SIGN_P521: 132,
KEYCERT_SIGN_RSA2048: 256,
KEYCERT_SIGN_RSA3072: 384,
KEYCERT_SIGN_RSA4096: 512,
KEYCERT_SIGN_ED25519: 64,
KEYCERT_SIGN_ED25519PH: 64,
KEYCERT_SIGN_DSA_SHA1: KEYCERT_SIGN_DSA_SHA1_SIZE,
KEYCERT_SIGN_P256: KEYCERT_SIGN_P256_SIZE,
KEYCERT_SIGN_P384: KEYCERT_SIGN_P384_SIZE,
KEYCERT_SIGN_P521: KEYCERT_SIGN_P521_SIZE,
KEYCERT_SIGN_RSA2048: KEYCERT_SIGN_RSA2048_SIZE,
KEYCERT_SIGN_RSA3072: KEYCERT_SIGN_RSA3072_SIZE,
KEYCERT_SIGN_RSA4096: KEYCERT_SIGN_RSA4096_SIZE,
KEYCERT_SIGN_ED25519: KEYCERT_SIGN_ED25519_SIZE,
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.
func (key_certificate KeyCertificate) CryptoSize() (size int) {
sizes := map[int]int{
KEYCERT_CRYPTO_ELG: KEYCERT_CRYPTO_ELG_SIZE,
KEYCERT_CRYPTO_P256: KEYCERT_CRYPTO_P256_SIZE,
KEYCERT_CRYPTO_P384: KEYCERT_CRYPTO_P384_SIZE,
KEYCERT_CRYPTO_P521: KEYCERT_CRYPTO_P521_SIZE,
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)]
}
@@ -203,47 +291,49 @@ func (key_certificate KeyCertificate) SignatureSize() (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 {
// return nil, err
//}
if err != nil {
log.WithError(err).Error("Failed to read Certificate")
return
}
if len(bytes) < KEYCERT_MIN_SIZE {
err = errors.New("error parsing key certificate: not enough data")
remainder = bytes[KEYCERT_MIN_SIZE:]
log.WithError(err).Error("KeyCertificate data too short")
}
switch len(bytes) {
case 4:
key_certificate = &KeyCertificate{
Certificate: certificate,
spkType: Integer(bytes[4:]),
cpkType: Integer([]byte{0}),
}
case 5:
key_certificate = &KeyCertificate{
Certificate: certificate,
spkType: Integer(bytes[4:5]),
cpkType: Integer([]byte{0}),
}
case 6:
key_certificate = &KeyCertificate{
Certificate: certificate,
spkType: Integer(bytes[4:5]),
cpkType: Integer(bytes[6:]),
}
default:
key_certificate = &KeyCertificate{
Certificate: certificate,
spkType: Integer(bytes[4:5]),
cpkType: Integer(bytes[6:7]),
}
key_certificate = &KeyCertificate{
Certificate: certificate,
}
remainder = bytes[7:]
//key_certificate.PublicKey = NewPublicKey(bytes)
if len(bytes) >= 5 {
key_certificate.spkType = Integer(bytes[4:5])
}
if len(bytes) >= 7 {
key_certificate.cpkType = Integer(bytes[6:7])
}
log.WithFields(logrus.Fields{
"spk_type": key_certificate.spkType.Int(),
"cpk_type": key_certificate.cpkType.Int(),
"remainder_length": len(remainder),
}).Debug("Successfully created new KeyCertificate")
return
}
// KeyCertificateFromCertificate returns a *KeyCertificate from a *Certificate.
func KeyCertificateFromCertificate(certificate *Certificate) *KeyCertificate {
k, _, _ := NewKeyCertificate(certificate.RawBytes())
func KeyCertificateFromCertificate(certificate Certificate) *KeyCertificate {
log.Debug("Creating KeyCertificate from Certificate")
// k, _, _ := NewKeyCertificate(certificate.RawBytes())
k, _, err := NewKeyCertificate(certificate.RawBytes())
if err != nil {
log.WithError(err).Error("Failed to create KeyCertificate from Certificate")
} else {
log.Debug("Successfully created KeyCertificate from Certificate")
}
return k
}

View File

@@ -0,0 +1,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.

View File

@@ -4,12 +4,16 @@ package keys_and_cert
import (
"errors"
"github.com/go-i2p/go-i2p/lib/util/logger"
. "github.com/go-i2p/go-i2p/lib/common/certificate"
. "github.com/go-i2p/go-i2p/lib/common/key_certificate"
"github.com/go-i2p/go-i2p/lib/crypto"
log "github.com/sirupsen/logrus"
"github.com/sirupsen/logrus"
)
var log = logger.GetGoI2PLogger()
// Sizes of various KeysAndCert structures and requirements
const (
KEYS_AND_CERT_PUBKEY_SIZE = 256
@@ -79,104 +83,50 @@ type KeysAndCert struct {
}
// Bytes returns the entire KeyCertificate in []byte form, trims payload to specified length.
func (keys_and_cert *KeysAndCert) Bytes() []byte {
return keys_and_cert.KeyCertificate.Bytes()
func (keys_and_cert KeysAndCert) Bytes() []byte {
bytes := keys_and_cert.KeyCertificate.Bytes()
log.WithFields(logrus.Fields{
"bytes_length": len(bytes),
}).Debug("Retrieved bytes from KeysAndCert")
return bytes
}
// PublicKey returns the public key as a crypto.PublicKey.
func (keys_and_cert *KeysAndCert) PublicKey() (key crypto.PublicKey) {
/*cert := keys_and_cert.Certificate()
cert_len := cert.Length()
if err != nil {
return
}
if cert_len == 0 {
// No Certificate is present, return the KEYS_AND_CERT_PUBKEY_SIZE byte
// PublicKey space as ElgPublicKey.
var elg_key crypto.ElgPublicKey
copy(keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE], elg_key[:])
key = elg_key
} else {
// A Certificate is present in this KeysAndCert
cert_type := cert.Type()
if cert_type == CERT_KEY {
// This KeysAndCert contains a Key Certificate, construct
// a PublicKey from the data in the KeysAndCert and
// any additional data in the Certificate.
key, err = KeyCertificateFromCertificate(cert).ConstructPublicKey(
keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE],
)
} else {
// Key Certificate is not present, return the KEYS_AND_CERT_PUBKEY_SIZE byte
// PublicKey space as ElgPublicKey. No other Certificate
// types are currently in use.
var elg_key crypto.ElgPublicKey
copy(keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE], elg_key[:])
key = elg_key
log.WithFields(log.Fields{
"at": "(KeysAndCert) PublicKey",
"cert_type": cert_type,
}).Warn("unused certificate type observed")
}
}
return*/
return keys_and_cert.publicKey
}
// SigningPublicKey returns the signing public key.
func (keys_and_cert *KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey) {
/*cert := keys_and_cert.Certificate()
cert_len := cert.Length()
if err != nil {
return
}
if cert_len == 0 {
// No Certificate is present, return the KEYS_AND_CERT_SPK_SIZE byte
// SigningPublicKey space as legacy DSA SHA1 SigningPublicKey.
var dsa_pk crypto.DSAPublicKey
copy(dsa_pk[:], keys_and_cert[KEYS_AND_CERT_PUBKEY_SIZE:KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE])
signing_public_key = dsa_pk
} else {
// A Certificate is present in this KeysAndCert
cert_type := cert.Type()
if cert_type == CERT_KEY {
// This KeysAndCert contains a Key Certificate, construct
// a SigningPublicKey from the data in the KeysAndCert and
// any additional data in the Certificate.
signing_public_key, err = KeyCertificateFromCertificate(cert).ConstructSigningPublicKey(
keys_and_cert[KEYS_AND_CERT_PUBKEY_SIZE : KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE],
)
} else {
// Key Certificate is not present, return the KEYS_AND_CERT_SPK_SIZE byte
// SigningPublicKey space as legacy SHA DSA1 SigningPublicKey.
// No other Certificate types are currently in use.
var dsa_pk crypto.DSAPublicKey
copy(dsa_pk[:], keys_and_cert[KEYS_AND_CERT_PUBKEY_SIZE:KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE])
signing_public_key = dsa_pk
}
}*/
return keys_and_cert.signingPublicKey
}
// Certfificate returns the certificate.
func (keys_and_cert *KeysAndCert) Certificate() (cert *Certificate) {
func (keys_and_cert *KeysAndCert) Certificate() (cert Certificate) {
return keys_and_cert.KeyCertificate.Certificate
}
//
// Read a KeysAndCert from a slice of bytes, retuning it and the remaining data as well as any errors
// encoutered parsing the KeysAndCert.
//
// ReadKeysAndCert returns KeysAndCert from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
// ReadKeysAndCert creates a new *KeysAndCert from []byte using ReadKeysAndCert.
// Returns a pointer to KeysAndCert unlike ReadKeysAndCert.
func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte, err error) {
/*data_len := len(data)
if data_len < KEYS_AND_CERT_MIN_SIZE {
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Reading KeysAndCert from data")
data_len := len(data)
// keys_and_cert = KeysAndCert{}
if data_len < KEYS_AND_CERT_MIN_SIZE && data_len > KEYS_AND_CERT_DATA_SIZE {
log.WithFields(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:])
return
} else if data_len < KEYS_AND_CERT_DATA_SIZE {
log.WithFields(logrus.Fields{
"at": "ReadKeysAndCert",
"data_len": data_len,
"required_len": KEYS_AND_CERT_MIN_SIZE,
@@ -185,56 +135,33 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
return
}
keys_and_cert = KeysAndCert(data[:KEYS_AND_CERT_MIN_SIZE])
cert, _ := keys_and_cert.Certificate()
cert_len := cert.Length()
if cert_len == 0 {
remainder = data[KEYS_AND_CERT_MIN_SIZE:]
keys_and_cert.KeyCertificate, remainder, err = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
if err != nil {
log.WithError(err).Error("Failed to create KeyCertificate")
return
}
if data_len < KEYS_AND_CERT_MIN_SIZE+cert_len {
keys_and_cert = append(keys_and_cert, data[KEYS_AND_CERT_MIN_SIZE:]...)
//err = cert_len_err
} else {
keys_and_cert = append(keys_and_cert, data[KEYS_AND_CERT_MIN_SIZE:KEYS_AND_CERT_MIN_SIZE+cert_len]...)
remainder = data[KEYS_AND_CERT_MIN_SIZE+cert_len:]
}*/
keys_and_cert_pointer, remainder, err := NewKeysAndCert(data)
keys_and_cert = *keys_and_cert_pointer
// TODO: this only supports one key type right now and it's the old key type, but the layout is the same.
// a case-switch which sets the size of the SPK and the PK should be used to replace the referenced KEYS_AND_CERT_PUBKEY_SIZE
// and KEYS_AND_CERT_SPK_SIZE constants in the future.
keys_and_cert.publicKey, err = keys_and_cert.KeyCertificate.ConstructPublicKey(data[:keys_and_cert.KeyCertificate.CryptoSize()])
if err != nil {
log.WithError(err).Error("Failed to construct PublicKey")
return
}
keys_and_cert.signingPublicKey, err = keys_and_cert.KeyCertificate.ConstructSigningPublicKey(data[KEYS_AND_CERT_DATA_SIZE-keys_and_cert.KeyCertificate.SignatureSize() : KEYS_AND_CERT_DATA_SIZE])
if err != nil {
log.WithError(err).Error("Failed to construct SigningPublicKey")
return
}
padding := data[KEYS_AND_CERT_PUBKEY_SIZE : KEYS_AND_CERT_DATA_SIZE-KEYS_AND_CERT_SPK_SIZE]
keys_and_cert.padding = padding
log.WithFields(logrus.Fields{
"public_key_type": keys_and_cert.KeyCertificate.PublicKeyType(),
"signing_public_key_type": keys_and_cert.KeyCertificate.SigningPublicKeyType(),
"padding_length": len(padding),
"remainder_length": len(remainder),
}).Debug("Successfully read KeysAndCert")
return
}
// NewKeysAndCert 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) {
data_len := len(data)
keys_and_cert = &KeysAndCert{}
if data_len < KEYS_AND_CERT_MIN_SIZE {
log.WithFields(log.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")
return
}
cert, remainder, err := NewKeyCertificate(data)
keys_and_cert.KeyCertificate = cert
if err != nil {
return nil, nil, err
}
padding := data[KEYS_AND_CERT_MIN_SIZE+cert.Length():]
keys_and_cert.padding = padding
publicKey, err := cert.ConstructPublicKey(padding)
keys_and_cert.publicKey = publicKey
if err != nil {
return nil, nil, err
}
signingPublicKey, err := cert.ConstructSigningPublicKey(padding)
keys_and_cert.signingPublicKey = signingPublicKey
if err != nil {
return nil, nil, err
}
return keys_and_cert, remainder, err
}

View File

@@ -6,23 +6,17 @@ import (
"github.com/stretchr/testify/assert"
)
func TestCertificateWithMissingData(t *testing.T) {
/*func TestCertificateWithMissingData(t *testing.T) {
assert := assert.New(t)
cert_data := []byte{0x05, 0x00, 0x04, 0x00, 0x01}
data := make([]byte, 128+256)
data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data)
cert := keys_and_cert.Certificate()
_, _, err := NewKeysAndCert(data)
if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error())
}
cert_bytes := cert.Bytes()
if assert.Equal(len(cert_data), len(cert_bytes)) {
assert.Equal(cert_bytes, cert_data, "keys_and_cert.Certificate() did not return available data when cert was missing some data")
}
}
}*/
func TestCertificateWithValidData(t *testing.T) {
assert := assert.New(t)
@@ -31,9 +25,10 @@ func TestCertificateWithValidData(t *testing.T) {
data := make([]byte, 128+256)
data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data)
assert.Nil(err)
cert := keys_and_cert.Certificate()
assert.Nil(err)
cert_bytes := cert.Bytes()
if assert.Equal(len(cert_data), len(cert_bytes)) {
assert.Equal(cert_bytes, cert_data, "keys_and_cert.Certificate() did not return correct data with valid cert")
@@ -168,7 +163,7 @@ func TestSigningPublicKeyWithKeyCertificate(t *testing.T) {
assert.Equal(len(signing_pub_key_data), signing_pub_key.Len())
}
func TestReadKeysAndCertWithMissingData(t *testing.T) {
func TestNewKeysAndCertWithMissingData(t *testing.T) {
assert := assert.New(t)
cert_data := make([]byte, 128)
@@ -177,10 +172,9 @@ func TestReadKeysAndCertWithMissingData(t *testing.T) {
if assert.NotNil(err) {
assert.Equal("error parsing KeysAndCert: data is smaller than minimum valid size", err.Error())
}
}
func TestReadKeysAndCertWithMissingCertData(t *testing.T) {
func TestNewKeysAndCertWithMissingCertData(t *testing.T) {
assert := assert.New(t)
cert_data := make([]byte, 128+256)
@@ -192,7 +186,7 @@ func TestReadKeysAndCertWithMissingCertData(t *testing.T) {
}
}
func TestReadKeysAndCertWithValidDataWithCertificate(t *testing.T) {
func TestNewKeysAndCertWithValidDataWithCertificate(t *testing.T) {
assert := assert.New(t)
cert_data := make([]byte, 128+256)
@@ -202,7 +196,7 @@ func TestReadKeysAndCertWithValidDataWithCertificate(t *testing.T) {
assert.Nil(err)
}
func TestReadKeysAndCertWithValidDataWithoutCertificate(t *testing.T) {
func TestNewKeysAndCertWithValidDataWithoutCertificate(t *testing.T) {
assert := assert.New(t)
cert_data := make([]byte, 128+256)
@@ -212,7 +206,7 @@ func TestReadKeysAndCertWithValidDataWithoutCertificate(t *testing.T) {
assert.Nil(err)
}
func TestReadKeysAndCertWithValidDataWithCertificateAndRemainder(t *testing.T) {
func TestNewKeysAndCertWithValidDataWithCertificateAndRemainder(t *testing.T) {
assert := assert.New(t)
cert_data := make([]byte, 128+256)
@@ -224,7 +218,7 @@ func TestReadKeysAndCertWithValidDataWithCertificateAndRemainder(t *testing.T) {
assert.Nil(err)
}
func TestReadKeysAndCertWithValidDataWithoutCertificateAndRemainder(t *testing.T) {
func TestNewKeysAndCertWithValidDataWithoutCertificateAndRemainder(t *testing.T) {
assert := assert.New(t)
cert_data := make([]byte, 128+256)

View File

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

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

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

View File

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

View File

@@ -4,6 +4,9 @@ package lease_set
import (
"errors"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
. "github.com/go-i2p/go-i2p/lib/common/certificate"
. "github.com/go-i2p/go-i2p/lib/common/data"
. "github.com/go-i2p/go-i2p/lib/common/destination"
@@ -12,9 +15,10 @@ import (
. "github.com/go-i2p/go-i2p/lib/common/lease"
. "github.com/go-i2p/go-i2p/lib/common/signature"
"github.com/go-i2p/go-i2p/lib/crypto"
log "github.com/sirupsen/logrus"
)
var log = logger.GetGoI2PLogger()
// Sizes of various structures in an I2P LeaseSet
const (
LEASE_SET_PUBKEY_SIZE = 256
@@ -133,7 +137,16 @@ type LeaseSet struct {
// Destination returns the Destination as []byte.
func (lease_set LeaseSet) Destination() (destination Destination, err error) {
keys_and_cert, _, err := ReadKeysAndCert(lease_set)
if err != nil {
log.WithError(err).Error("Failed to read KeysAndCert from LeaseSet")
return
}
destination, _, err = ReadDestination(keys_and_cert.Bytes())
if err != nil {
log.WithError(err).Error("Failed to read Destination from KeysAndCert")
} else {
log.Debug("Successfully retrieved Destination from LeaseSet")
}
return
}
@@ -143,7 +156,7 @@ func (lease_set LeaseSet) PublicKey() (public_key crypto.ElgPublicKey, err error
_, remainder, err := ReadKeysAndCert(lease_set)
remainder_len := len(remainder)
if remainder_len < LEASE_SET_PUBKEY_SIZE {
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "(LeaseSet) PublicKey",
"data_len": remainder_len,
"required_len": LEASE_SET_PUBKEY_SIZE,
@@ -154,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,
@@ -187,6 +204,7 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK
var dsa_pk crypto.DSAPublicKey
copy(dsa_pk[:], lease_set[offset:offset+LEASE_SET_SPK_SIZE])
signing_public_key = dsa_pk
log.Debug("Retrieved legacy DSA SHA1 SigningPublicKey")
} else {
// A Certificate is present in this LeaseSet's Destination
cert_type := cert.Type()
@@ -197,14 +215,19 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK
signing_public_key, err = KeyCertificateFromCertificate(cert).ConstructSigningPublicKey(
lease_set[offset : offset+LEASE_SET_SPK_SIZE],
)
if err != nil {
log.WithError(err).Error("Failed to construct SigningPublicKey from KeyCertificate")
} else {
log.Debug("Retrieved SigningPublicKey from KeyCertificate")
}
} else {
// No Certificate is present, return the LEASE_SET_SPK_SIZE byte
// SigningPublicKey space as legacy DSA SHA1 SigningPublicKey.
var dsa_pk crypto.DSAPublicKey
copy(dsa_pk[:], lease_set[offset:offset+LEASE_SET_SPK_SIZE])
signing_public_key = dsa_pk
log.Debug("Retrieved legacy DSA SHA1 SigningPublicKey (Certificate present but not Key Certificate)")
}
}
return
}
@@ -212,13 +235,15 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK
// LeaseCount returns the numbert of leases specified by the LeaseCount value as int.
// returns errors encountered during parsing.
func (lease_set LeaseSet) LeaseCount() (count int, err error) {
log.Debug("Retrieving LeaseCount from LeaseSet")
_, remainder, err := ReadKeysAndCert(lease_set)
if err != nil {
log.WithError(err).Error("Failed to read KeysAndCert for LeaseCount")
return
}
remainder_len := len(remainder)
if remainder_len < LEASE_SET_PUBKEY_SIZE+LEASE_SET_SPK_SIZE+1 {
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "(LeaseSet) LeaseCount",
"data_len": remainder_len,
"required_len": LEASE_SET_PUBKEY_SIZE + LEASE_SET_SPK_SIZE + 1,
@@ -230,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
}
@@ -243,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++ {
@@ -257,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,
@@ -270,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()) +
@@ -299,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,
@@ -309,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 +
@@ -327,14 +363,17 @@ func (lease_set LeaseSet) Verify() error {
//if err != nil {
// return err
//}
log.Warn("LeaseSet verification not implemented")
return nil // verifier.Verify(data, lease_set.Signature())
}
// NewestExpiration returns the newest lease expiration as an I2P Date.
// Returns errors encountered during parsing.
func (lease_set LeaseSet) NewestExpiration() (newest Date, err error) {
log.Debug("Finding newest expiration in LeaseSet")
leases, err := lease_set.Leases()
if err != nil {
log.WithError(err).Error("Failed to retrieve Leases for NewestExpiration")
return
}
newest = Date{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
@@ -344,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}
@@ -361,5 +403,6 @@ func (lease_set LeaseSet) OldestExpiration() (earliest Date, err error) {
earliest = date
}
}
log.WithField("oldest_expiration", earliest.Time()).Debug("Found oldest expiration in LeaseSet")
return
}

View File

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

View File

@@ -0,0 +1,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
```

View File

@@ -3,9 +3,15 @@ package router_address
import (
"errors"
"fmt"
"net"
"strconv"
"strings"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
. "github.com/go-i2p/go-i2p/lib/common/data"
log "github.com/sirupsen/logrus"
)
// Minimum number of bytes in a valid RouterAddress
@@ -13,6 +19,8 @@ const (
ROUTER_ADDRESS_MIN_SIZE = 9
)
var log = logger.GetGoI2PLogger()
/*
[RouterAddress]
Accurate for version 0.9.49
@@ -63,71 +71,249 @@ options :: Mapping
//
// https://geti2p.net/spec/common-structures#routeraddress
type RouterAddress struct {
cost *Integer
expiration *Date
Transport_Style *I2PString
options *Mapping
parserErr error
TransportCost *Integer
ExpirationDate *Date
TransportType I2PString
TransportOptions *Mapping
}
// Network implements net.Addr. It returns the transport type plus 4 or 6
func (router_address *RouterAddress) Network() string {
log.Debug("Getting network for RouterAddress")
if router_address.TransportType == nil {
log.Warn("TransportType is nil in RouterAddress")
return ""
}
str, err := router_address.TransportType.Data()
if err != nil {
log.WithError(err).Error("Failed to get TransportType data")
return ""
}
network := string(str) + router_address.IPVersion()
log.WithField("network", network).Debug("Retrieved network for RouterAddress")
return network
}
// IPVersion returns a string "4" for IPv4 or 6 for IPv6
func (router_address *RouterAddress) IPVersion() string {
log.Debug("Getting IP version for RouterAddress")
str, err := router_address.CapsString().Data()
if err != nil {
log.WithError(err).Error("Failed to get CapsString data")
return ""
}
if strings.HasSuffix(str, "6") {
log.Debug("IP version is IPv6")
return "6"
}
log.Debug("IP version is IPv4")
return "4"
}
func (router_address *RouterAddress) UDP() bool {
// return strings.HasPrefix(strings.ToLower(router_address.Network()), "ssu")
log.Debug("Checking if RouterAddress is UDP")
isUDP := strings.HasPrefix(strings.ToLower(router_address.Network()), "ssu")
log.WithField("is_udp", isUDP).Debug("Checked if RouterAddress is UDP")
return isUDP
}
// String implements net.Addr. It returns the IP address, followed by the options
func (router_address *RouterAddress) String() string {
log.Debug("Converting RouterAddress to string")
var rv []string
rv = append(rv, string(router_address.TransportStyle()))
rv = append(rv, string(router_address.HostString()))
rv = append(rv, string(router_address.PortString()))
rv = append(rv, string(router_address.StaticKeyString()))
rv = append(rv, string(router_address.InitializationVectorString()))
rv = append(rv, string(router_address.ProtocolVersionString()))
if router_address.UDP() {
rv = append(rv, string(router_address.IntroducerHashString(0)))
rv = append(rv, string(router_address.IntroducerExpirationString(0)))
rv = append(rv, string(router_address.IntroducerTagString(0)))
rv = append(rv, string(router_address.IntroducerHashString(1)))
rv = append(rv, string(router_address.IntroducerExpirationString(1)))
rv = append(rv, string(router_address.IntroducerTagString(1)))
rv = append(rv, string(router_address.IntroducerHashString(2)))
rv = append(rv, string(router_address.IntroducerExpirationString(2)))
rv = append(rv, string(router_address.IntroducerTagString(2)))
}
str := strings.TrimSpace(strings.Join(rv, " "))
log.WithField("router_address_string", str).Debug("Converted RouterAddress to string")
return str
}
var ex_addr net.Addr = &RouterAddress{}
// Bytes returns the router address as a []byte.
func (router_address RouterAddress) Bytes() []byte {
log.Debug("Converting RouterAddress to bytes")
bytes := make([]byte, 0)
bytes = append(bytes, router_address.cost.Bytes()...)
bytes = append(bytes, router_address.expiration.Bytes()...)
strData, err := router_address.Transport_Style.Data()
bytes = append(bytes, router_address.TransportCost.Bytes()...)
bytes = append(bytes, router_address.ExpirationDate.Bytes()...)
strData, err := router_address.TransportType.Data()
if err != nil {
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"error": err,
}).Error("RouterAddress.Bytes: error getting Transport_Style bytes")
}).Error("RouterAddress.Bytes: error getting transport_style bytes")
} else {
bytes = append(bytes, strData...)
}
//bytes = append(bytes, router_address.options.Bytes()...)
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.
func (router_address RouterAddress) checkValid() (err error, exit bool) {
/*addr_len := len(router_address)
exit = false
if addr_len == 0 {
log.WithFields(log.Fields{
"at": "(RouterAddress) checkValid",
"reason": "no data",
}).Error("invalid router address")
err = errors.New("error parsing RouterAddress: no data")
exit = true
} else if addr_len < ROUTER_ADDRESS_MIN_SIZE {
log.WithFields(log.Fields{
"at": "(RouterAddress) checkValid",
"reason": "data too small (len < ROUTER_ADDRESS_MIN_SIZE)",
}).Warn("router address format warning")
err = errors.New("warning parsing RouterAddress: data too small")
}*/
if router_address.parserErr != nil {
exit = true
}
return
}
@@ -135,62 +321,41 @@ func (router_address RouterAddress) checkValid() (err error, exit bool) {
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []byte, err error) {
if data == nil || len(data) == 0 {
log.WithField("at", "(RouterAddress) ReadRouterAddress").Error("no data")
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")
router_address.parserErr = err
return
}
cost, remainder, err := NewInteger([]byte{data[0]}, 1)
router_address.cost = cost
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.parserErr = err
}
expiration, remainder, err := NewDate(remainder)
router_address.expiration = expiration
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.parserErr = err
}
Transport_Style, remainder, err := NewI2PString(remainder)
router_address.Transport_Style = Transport_Style
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",
"reason": "error parsing transport_style",
}).Error("error parsing RouterAddress")
router_address.parserErr = err
}
options, remainder, errs := NewMapping(remainder)
var errs []error
router_address.TransportOptions, remainder, errs = NewMapping(remainder)
for _, err := range errs {
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "(RouterAddress) ReadNewRouterAddress",
"reason": "error parsing options",
}).Error("error parsing RouterAddress")
router_address.parserErr = err
}
router_address.options = options
if err != nil {
log.WithFields(log.Fields{
"at": "(RouterAddress) ReadNewRouterAddress",
"reason": "error parsing options",
}).Error("error parsing RouterAddress")
router_address.parserErr = err
"error": err,
}).Error("error parsing RozuterAddress")
}
return
}
// NewRouterAddress creates a new *RouterAddress from []byte using ReadRouterAddress.
// Returns a pointer to RouterAddress unlike ReadRouterAddress.
func NewRouterAddress(data []byte) (router_address *RouterAddress, remainder []byte, err error) {
objrouteraddress, remainder, err := ReadRouterAddress(data)
router_address = &objrouteraddress
return
}

View File

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

View File

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

View File

@@ -3,8 +3,12 @@ package router_identity
import (
. "github.com/go-i2p/go-i2p/lib/common/keys_and_cert"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
)
var log = logger.GetGoI2PLogger()
/*
[RouterIdentity]
Accurate for version 0.9.49
@@ -20,24 +24,26 @@ Identical to KeysAndCert.
//
// https://geti2p.net/spec/common-structures#routeridentity
type RouterIdentity struct {
*KeysAndCert
KeysAndCert
}
// ReadRouterIdentity returns RouterIdentity from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder []byte, err error) {
keys_and_cert, remainder, err := NewKeysAndCert(data)
log.WithFields(logrus.Fields{
"input_length": len(data),
}).Debug("Reading RouterIdentity from data")
keys_and_cert, remainder, err := ReadKeysAndCert(data)
if err != nil {
log.WithError(err).Error("Failed to read KeysAndCert for RouterIdentity")
return
}
router_identity = RouterIdentity{
keys_and_cert,
}
return
}
// NewRouterIdentity creates a new *RouterIdentity from []byte using ReadRouterIdentity.
// Returns a pointer to RouterIdentity unlike ReadRouterIdentity.
func NewRouterIdentity(data []byte) (router_identity *RouterIdentity, remainder []byte, err error) {
objrouter_identity, remainder, err := ReadRouterIdentity(data)
router_identity = &objrouter_identity
log.WithFields(logrus.Fields{
"remainder_length": len(remainder),
}).Debug("Successfully read RouterIdentity")
return
}

View File

@@ -0,0 +1,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
```

View File

@@ -3,18 +3,27 @@ package router_info
import (
"errors"
"net"
"strconv"
"strings"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
. "github.com/go-i2p/go-i2p/lib/common/data"
. "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
MAX_GOOD_VERSION = 99
)
/*
[RouterInfo]
Accurate for version 0.9.49
@@ -99,7 +108,7 @@ signature :: Signature
//
// https://geti2p.net/spec/common-structures#routerinfo
type RouterInfo struct {
router_identity *RouterIdentity
router_identity RouterIdentity
published *Date
size *Integer
addresses []*RouterAddress
@@ -108,13 +117,9 @@ type RouterInfo struct {
signature *Signature
}
var routerInfoTest net.Addr = &RouterInfo{}
// Bytes returns the RouterInfo as a []byte suitable for writing to a stream.
func (router_info RouterInfo) Bytes() ([]byte, error) {
var err error
var bytes []byte
func (router_info RouterInfo) Bytes() (bytes []byte, err error) {
log.Debug("Converting RouterInfo to bytes")
bytes = append(bytes, router_info.router_identity.KeysAndCert.Bytes()...)
bytes = append(bytes, router_info.published.Bytes()...)
bytes = append(bytes, router_info.size.Bytes()...)
@@ -122,45 +127,39 @@ func (router_info RouterInfo) Bytes() ([]byte, error) {
bytes = append(bytes, router_address.Bytes()...)
}
bytes = append(bytes, router_info.peer_size.Bytes()...)
//bytes = append(bytes, router_info.options.Bytes()...)
bytes = append(bytes, router_info.options.Data()...)
bytes = append(bytes, []byte(*router_info.signature)...)
log.WithField("bytes_length", len(bytes)).Debug("Converted RouterInfo to bytes")
return bytes, err
}
// Network Implements net.Addr, returns comma-separated list of transport types
func (router_info *RouterInfo) Network() string {
var str []string
for _, addr := range router_info.addresses {
t, err := addr.Transport_Style.Data()
if err != nil {
return strings.Join(str, ",")
}
str = append(str, t)
func (router_info RouterInfo) String() string {
log.Debug("Converting RouterInfo to string")
str := "Certificate: " + string(router_info.router_identity.KeysAndCert.Bytes())
str += "Published: " + string(router_info.published.Bytes())
str += "Addresses:" + string(router_info.size.Bytes())
for index, router_address := range router_info.addresses {
str += "Address " + strconv.Itoa(index) + ": " + router_address.String()
}
return strings.Join(str, ",")
}
// String Implements net.Addr, returns router-info `Bytes` converted to a string
func (router_info *RouterInfo) String() string {
bytes, err := router_info.Bytes()
if err != nil {
// TODO handle this issue
return ""
}
return string(bytes)
str += "Peer Size: " + string(router_info.peer_size.Bytes())
str += "Options: " + string(router_info.options.Data())
str += "Signature: " + string([]byte(*router_info.signature))
log.WithField("string_length", len(str)).Debug("Converted RouterInfo to string")
return str
}
// RouterIdentity returns the router identity as *RouterIdentity.
func (router_info *RouterInfo) RouterIdentity() *RouterIdentity {
return router_info.router_identity
return &router_info.router_identity
}
// IndentHash returns the identity hash (sha256 sum) for this RouterInfo.
func (router_info *RouterInfo) IdentHash() Hash {
ri := router_info.RouterIdentity()
h := HashData(ri.KeysAndCert.Certificate().Data())
return h
log.Debug("Calculating IdentHash for RouterInfo")
data, _ := router_info.RouterIdentity().KeyCertificate.Data()
hash := HashData(data)
log.WithField("hash", hash).Debug("Calculated IdentHash for RouterInfo")
return HashData(data)
}
// Published returns the date this RouterInfo was published as an I2P Date.
@@ -170,11 +169,14 @@ func (router_info *RouterInfo) Published() *Date {
// RouterAddressCount returns the count of RouterAddress in this RouterInfo as a Go integer.
func (router_info *RouterInfo) RouterAddressCount() int {
return router_info.size.Int()
count := router_info.size.Int()
log.WithField("count", count).Debug("Retrieved RouterAddressCount from RouterInfo")
return count
}
// RouterAddresses returns all RouterAddresses for this RouterInfo as []*RouterAddress.
func (router_info *RouterInfo) RouterAddresses() []*RouterAddress {
log.WithField("address_count", len(router_info.addresses)).Debug("Retrieved RouterAddresses from RouterInfo")
return router_info.addresses
}
@@ -190,86 +192,36 @@ func (router_info RouterInfo) Options() (mapping Mapping) {
return *router_info.options
}
//
// Return the signature of this router info
//
// Signature returns the signature for this RouterInfo as an I2P Signature.
func (router_info RouterInfo) Signature() (signature Signature) {
return *router_info.signature
}
//
// Used during parsing to determine where in the RouterInfo the Mapping data begins.
//
/*func (router_info RouterInfo) optionsLocation() (location int) {
data, remainder, err := ReadRouterIdentity(router_info)
if err != nil {
return
}
location += len(data)
remainder_len := len(remainder)
if remainder_len < 9 {
log.WithFields(log.Fields{
"at": "(RouterInfo) optionsLocation",
"data_len": remainder_len,
"required_len": 9,
"reason": "not enough data",
}).Error("error parsing router info")
err = errors.New("error parsing router addresses: not enough data")
return
}
location += 9
remaining := remainder[9:]
var router_address RouterAddress
var router_addresses []RouterAddress
addr_count, cerr := router_info.RouterAddressCount()
if cerr != nil {
err = cerr
return
}
for i := 0; i < addr_count; i++ {
router_address, remaining, err = ReadRouterAddress(remaining)
if err == nil {
location += len(router_address)
router_addresses = append(router_addresses, router_address)
}
}
location += 1
return
}*/
//
// Used during parsing to determine the size of the options in the RouterInfo.
//
/*func (router_info RouterInfo) optionsSize() (size int) {
head := router_info.optionsLocation()
s := Integer(router_info[head : head+2])
size = s.Int() + 2
return
}*/
// Network implements net.Addr
func (router_info RouterInfo) Network() string {
return "i2p"
}
// ReadRouterInfo returns RouterInfo from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error) {
identity, remainder, err := NewRouterIdentity(bytes)
info.router_identity = identity
log.WithField("input_length", len(bytes)).Debug("Reading RouterInfo from bytes")
info.router_identity, remainder, err = ReadRouterIdentity(bytes)
if err != nil {
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "(RouterInfo) ReadRouterInfo",
"data_len": len(bytes),
"required_len": ROUTER_INFO_MIN_SIZE,
"reason": "not enough data",
}).Error("error parsing router info")
err = errors.New("error parsing router info: not enough data")
return
}
date, remainder, err := NewDate(remainder)
info.published = date
info.published, remainder, err = NewDate(remainder)
if err != nil {
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "(RouterInfo) ReadRouterInfo",
"data_len": len(remainder),
"required_len": DATE_SIZE,
@@ -277,38 +229,38 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
}).Error("error parsing router info")
err = errors.New("error parsing router info: not enough data")
}
size, remainder, err := NewInteger(remainder, 1)
info.size = size
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(),
"reason": "not enough data",
}).Error("error parsing router info")
err = errors.New("error parsing router info: not enough data")
"required_len": info.size.Int(),
"reason": "read error",
}).Error("error parsing router info size")
}
addresses := make([]*RouterAddress, size.Int())
for i := 0; i < size.Int(); i++ {
address, remainder, 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 info")
}).Error("error parsing router address")
err = errors.New("error parsing router info: not enough data")
}
addresses = append(addresses, address)
info.addresses = append(info.addresses, &address)
}
info.addresses = addresses
peer_size := Integer(remainder[:1])
info.peer_size = &peer_size
remainder = remainder[1:]
options, remainder, errs := NewMapping(remainder)
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,
@@ -320,9 +272,9 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
}
err = errors.New("error parsing router info: " + estring)
}
info.options = options
info.signature, remainder, err = NewSignature(remainder)
if err != nil {
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "(RouterInfo) ReadRouterInfo",
"data_len": len(remainder),
//"required_len": MAPPING_SIZE,
@@ -330,13 +282,94 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
}).Error("error parsing router info")
err = errors.New("error parsing router info: not enough data")
}
log.WithFields(logrus.Fields{
"router_identity": info.router_identity,
"published": info.published,
"address_count": len(info.addresses),
"remainder_length": len(remainder),
}).Debug("Successfully read RouterInfo")
return
}
// 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
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))
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))
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" {
if v[1] == "9" {
val, _ := strconv.Atoi(v[2])
if val >= MIN_GOOD_VERSION && val <= MAX_GOOD_VERSION {
return true
}
}
}
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")
reachable := strings.Contains(caps, "R")
log.WithFields(logrus.Fields{
"reachable": reachable,
"reason": "R capability",
}).Debug("Checked RouterInfo reachability")
return reachable
}

View File

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

View File

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

View File

@@ -1,6 +1,8 @@
// Package session_key implements the I2P SessionKey common data structure
package session_key
import log "github.com/sirupsen/logrus"
/*
[SessionKey]
Accurate for version 0.9.49
@@ -22,13 +24,20 @@ type SessionKey [32]byte
// Returns a list of errors that occurred during parsing.
func ReadSessionKey(bytes []byte) (info SessionKey, remainder []byte, err error) {
// TODO: stub
log.Warn("ReadSessionKey is not implemented")
return
}
// NewSessionKey creates a new *SessionKey from []byte using ReadSessionKey.
// Returns a pointer to SessionKey unlike ReadSessionKey.
func NewSessionKey(data []byte) (session_key *SessionKey, remainder []byte, err error) {
log.WithField("input_length", len(data)).Debug("Creating new SessionKey")
sessionKey, remainder, err := ReadSessionKey(data)
if err != nil {
log.WithError(err).Error("Failed to create new SessionKey")
return nil, remainder, err
}
session_key = &sessionKey
log.Debug("Successfully created new SessionKey")
return
}

View File

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

View File

@@ -1,6 +1,13 @@
// Package session_tag implements the I2P SessionTag common data structure
package session_tag
import (
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
)
var log = logger.GetGoI2PLogger()
/*
[SessionKey]
Accurate for version 0.9.49
@@ -22,13 +29,22 @@ type SessionTag [32]byte
// Returns a list of errors that occurred during parsing.
func ReadSessionTag(bytes []byte) (info SessionTag, remainder []byte, err error) {
// TODO: stub
log.Warn("ReadSessionTag is not implemented")
return
}
// NewSessionTag creates a new *SessionTag from []byte using ReadSessionTag.
// Returns a pointer to SessionTag unlike ReadSessionTag.
func NewSessionTag(data []byte) (session_tag *SessionTag, remainder []byte, err error) {
log.WithField("input_length", len(data)).Debug("Creating new SessionTag")
sessionTag, remainder, err := ReadSessionTag(data)
if err != nil {
log.WithError(err).Error("Failed to read SessionTag")
return nil, remainder, err
}
session_tag = &sessionTag
log.WithFields(logrus.Fields{
"remainder_length": len(remainder),
}).Debug("Successfully created new SessionTag")
return
}

View File

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

View File

@@ -1,6 +1,13 @@
// Package signature implements the I2P Signature common data structure
package signature
import (
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
)
var log = logger.GetGoI2PLogger()
// Lengths of signature keys
const (
DSA_SHA1_SIZE = 40
@@ -37,13 +44,25 @@ type Signature []byte
// Returns a list of errors that occurred during parsing.
func ReadSignature(bytes []byte) (info Signature, remainder []byte, err error) {
// TODO: stub
log.Warn("ReadSignature is not implemented")
return
}
// NewSignature creates a new *Signature from []byte using ReadSignature.
// Returns a pointer to Signature unlike ReadSignature.
func NewSignature(data []byte) (session_tag *Signature, remainder []byte, err error) {
sessionTag, remainder, err := ReadSignature(data)
session_tag = &sessionTag
log.WithField("input_length", len(data)).Debug("Creating new Signature")
// sessionTag, remainder, err := ReadSignature(data)
sig, remainder, err := ReadSignature(data)
if err != nil {
log.WithError(err).Error("Failed to read Signature")
return nil, remainder, err
}
session_tag = &sig
log.WithFields(logrus.Fields{
"signature_length": len(sig),
"remainder_length": len(remainder),
}).Debug("Successfully created new Signature")
return
}

111
lib/config/config.go Normal file
View File

@@ -0,0 +1,111 @@
package config
import (
"os"
"path/filepath"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/spf13/viper"
"gopkg.in/yaml.v3"
)
var (
CfgFile string
log = logger.GetGoI2PLogger()
)
func InitConfig() {
defaultConfigDir := filepath.Join(os.Getenv("HOME"), ".go-i2p")
defaultConfigFile := filepath.Join(defaultConfigDir, "config.yaml")
if CfgFile != "" {
// Use config file from the flag
viper.SetConfigFile(CfgFile)
} else {
// Create default config if it doesn't exist
if _, err := os.Stat(defaultConfigFile); os.IsNotExist(err) {
// Ensure directory exists
if err := os.MkdirAll(defaultConfigDir, 0o755); err != nil {
log.Fatalf("Could not create config directory: %s", err)
}
// Create default configuration
defaultConfig := struct {
BaseDir string `yaml:"base_dir"`
WorkingDir string `yaml:"working_dir"`
NetDB NetDbConfig `yaml:"netdb"`
Bootstrap BootstrapConfig `yaml:"bootstrap"`
}{
BaseDir: DefaultRouterConfig().BaseDir,
WorkingDir: DefaultRouterConfig().WorkingDir,
NetDB: *DefaultRouterConfig().NetDb,
Bootstrap: *DefaultRouterConfig().Bootstrap,
}
yamlData, err := yaml.Marshal(defaultConfig)
if err != nil {
log.Fatalf("Could not marshal default config: %s", err)
}
// Write default config file
if err := os.WriteFile(defaultConfigFile, yamlData, 0o644); err != nil {
log.Fatalf("Could not write default config file: %s", err)
}
log.Debugf("Created default configuration at: %s", defaultConfigFile)
}
// Set up viper to use the config file
viper.AddConfigPath(defaultConfigDir)
viper.SetConfigName("config")
viper.SetConfigType("yaml")
}
// Load defaults
setDefaults()
if err := viper.ReadInConfig(); err != nil {
log.Warnf("Error reading config file: %s", err)
} else {
log.Debugf("Using config file: %s", viper.ConfigFileUsed())
}
// Update RouterConfigProperties
UpdateRouterConfig()
}
func setDefaults() {
// Router defaults
viper.SetDefault("base_dir", DefaultRouterConfig().BaseDir)
viper.SetDefault("working_dir", DefaultRouterConfig().WorkingDir)
// NetDb defaults
viper.SetDefault("netdb.path", DefaultNetDbConfig.Path)
// Bootstrap defaults
viper.SetDefault("bootstrap.low_peer_threshold", DefaultBootstrapConfig.LowPeerThreshold)
viper.SetDefault("bootstrap.reseed_servers", []ReseedConfig{})
}
func UpdateRouterConfig() {
// Update Router configuration
RouterConfigProperties.BaseDir = viper.GetString("base_dir")
RouterConfigProperties.WorkingDir = viper.GetString("working_dir")
// Update NetDb configuration
RouterConfigProperties.NetDb = &NetDbConfig{
Path: viper.GetString("netdb.path"),
}
// Update Bootstrap configuration
var reseedServers []*ReseedConfig
if err := viper.UnmarshalKey("bootstrap.reseed_servers", &reseedServers); err != nil {
log.Warnf("Error parsing reseed servers: %s", err)
reseedServers = []*ReseedConfig{}
}
RouterConfigProperties.Bootstrap = &BootstrapConfig{
LowPeerThreshold: viper.GetInt("bootstrap.low_peer_threshold"),
ReseedServers: reseedServers,
}
}

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

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

View File

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

View File

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

View File

@@ -1 +1,177 @@
package crypto
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"fmt"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
)
var log = logger.GetGoI2PLogger()
// AESSymmetricKey represents a symmetric key for AES encryption/decryption
type AESSymmetricKey struct {
Key []byte // AES key (must be 16, 24, or 32 bytes for AES-128, AES-192, AES-256)
IV []byte // Initialization Vector (must be 16 bytes for AES)
}
// AESSymmetricEncrypter implements the Encrypter interface using AES
type AESSymmetricEncrypter struct {
Key []byte
IV []byte
}
// Encrypt encrypts data using AES-CBC with PKCS#7 padding
func (e *AESSymmetricEncrypter) Encrypt(data []byte) ([]byte, error) {
log.WithField("data_length", len(data)).Debug("Encrypting data")
block, err := aes.NewCipher(e.Key)
if err != nil {
log.WithError(err).Error("Failed to create AES cipher")
return nil, err
}
plaintext := pkcs7Pad(data, aes.BlockSize)
ciphertext := make([]byte, len(plaintext))
mode := cipher.NewCBCEncrypter(block, e.IV)
mode.CryptBlocks(ciphertext, plaintext)
log.WithField("ciphertext_length", len(ciphertext)).Debug("Data encrypted successfully")
return ciphertext, nil
}
// AESSymmetricDecrypter implements the Decrypter interface using AES
type AESSymmetricDecrypter struct {
Key []byte
IV []byte
}
// Decrypt decrypts data using AES-CBC with PKCS#7 padding
func (d *AESSymmetricDecrypter) Decrypt(data []byte) ([]byte, error) {
log.WithField("data_length", len(data)).Debug("Decrypting data")
block, err := aes.NewCipher(d.Key)
if err != nil {
log.WithError(err).Error("Failed to create AES cipher")
return nil, err
}
if len(data)%aes.BlockSize != 0 {
log.Error("Ciphertext is not a multiple of the block size")
return nil, fmt.Errorf("ciphertext is not a multiple of the block size")
}
plaintext := make([]byte, len(data))
mode := cipher.NewCBCDecrypter(block, d.IV)
mode.CryptBlocks(plaintext, data)
plaintext, err = pkcs7Unpad(plaintext)
if err != nil {
log.WithError(err).Error("Failed to unpad plaintext")
return nil, err
}
log.WithField("plaintext_length", len(plaintext)).Debug("Data decrypted successfully")
return plaintext, nil
}
// NewEncrypter creates a new AESSymmetricEncrypter
func (k *AESSymmetricKey) NewEncrypter() (Encrypter, error) {
log.Debug("Creating new AESSymmetricEncrypter")
return &AESSymmetricEncrypter{
Key: k.Key,
IV: k.IV,
}, nil
}
// Len returns the length of the key
func (k *AESSymmetricKey) Len() int {
return len(k.Key)
}
// NewDecrypter creates a new AESSymmetricDecrypter
func (k *AESSymmetricKey) NewDecrypter() (Decrypter, error) {
return &AESSymmetricDecrypter{
Key: k.Key,
IV: k.IV,
}, nil
}
func pkcs7Pad(data []byte, blockSize int) []byte {
log.WithFields(logrus.Fields{
"data_length": len(data),
"block_size": blockSize,
}).Debug("Applying PKCS#7 padding")
padding := blockSize - (len(data) % blockSize)
padText := bytes.Repeat([]byte{byte(padding)}, padding)
padded := append(data, padText...)
log.WithField("padded_length", len(padded)).Debug("PKCS#7 padding applied")
return append(data, padText...)
}
func pkcs7Unpad(data []byte) ([]byte, error) {
log.WithField("data_length", len(data)).Debug("Removing PKCS#7 padding")
length := len(data)
if length == 0 {
log.Error("Data is empty")
return nil, fmt.Errorf("data is empty")
}
padding := int(data[length-1])
if padding == 0 || padding > aes.BlockSize {
log.WithField("padding", padding).Error("Invalid padding")
return nil, fmt.Errorf("invalid padding")
}
paddingStart := length - padding
for i := paddingStart; i < length; i++ {
if data[i] != byte(padding) {
log.Error("Invalid padding")
return nil, fmt.Errorf("invalid padding")
}
}
unpadded := data[:paddingStart]
log.WithField("unpadded_length", len(unpadded)).Debug("PKCS#7 padding removed")
return unpadded, nil
}
// EncryptNoPadding encrypts data using AES-CBC without padding
func (e *AESSymmetricEncrypter) EncryptNoPadding(data []byte) ([]byte, error) {
if len(data)%aes.BlockSize != 0 {
return nil, fmt.Errorf("data length must be a multiple of block size")
}
block, err := aes.NewCipher(e.Key)
if err != nil {
return nil, err
}
ciphertext := make([]byte, len(data))
mode := cipher.NewCBCEncrypter(block, e.IV)
mode.CryptBlocks(ciphertext, data)
return ciphertext, nil
}
// DecryptNoPadding decrypts data using AES-CBC without padding
func (d *AESSymmetricDecrypter) DecryptNoPadding(data []byte) ([]byte, error) {
if len(data)%aes.BlockSize != 0 {
return nil, fmt.Errorf("data length must be a multiple of block size")
}
block, err := aes.NewCipher(d.Key)
if err != nil {
return nil, err
}
plaintext := make([]byte, len(data))
mode := cipher.NewCBCDecrypter(block, d.IV)
mode.CryptBlocks(plaintext, data)
return plaintext, nil
}

182
lib/crypto/aes_test.go Normal file
View File

@@ -0,0 +1,182 @@
package crypto
import (
"bytes"
"crypto/aes"
"crypto/rand"
"encoding/hex"
"testing"
)
func TestAESEncryptDecrypt(t *testing.T) {
key := make([]byte, 32) // 256-bit key
iv := make([]byte, aes.BlockSize)
_, err := rand.Read(key)
if err != nil {
t.Fatalf("Failed to generate random key: %v", err)
}
_, err = rand.Read(iv)
if err != nil {
t.Fatalf("Failed to generate random IV: %v", err)
}
symmetricKey := AESSymmetricKey{
Key: key,
IV: iv,
}
encrypter, err := symmetricKey.NewEncrypter()
if err != nil {
log.Fatalf("Error creating encrypter: %v", err)
}
decrypter, err := symmetricKey.NewDecrypter()
if err != nil {
log.Fatalf("Error creating decrypter: %v", err)
}
testCases := []struct {
name string
plaintext []byte
}{
{"Empty string", []byte("")},
{"Short string", []byte("Hello, World!")},
{"Long string", bytes.Repeat([]byte("A"), 1000)},
{"Exact block size", bytes.Repeat([]byte("A"), aes.BlockSize)},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
ciphertext, err := encrypter.Encrypt(tc.plaintext)
if err != nil {
t.Fatalf("Encryption failed: %v", err)
}
decrypted, err := decrypter.Decrypt(ciphertext)
if err != nil {
t.Fatalf("Decryption failed: %v", err)
}
if !bytes.Equal(tc.plaintext, decrypted) {
t.Errorf("Decrypted text doesn't match original plaintext.\nOriginal: %s\nDecrypted: %s",
hex.EncodeToString(tc.plaintext), hex.EncodeToString(decrypted))
}
})
}
}
func TestAESEncryptInvalidKey(t *testing.T) {
invalidKeys := [][]byte{
make([]byte, 15), // Too short
make([]byte, 17), // Invalid length
make([]byte, 31), // Too short for AES-256
make([]byte, 33), // Too long
make([]byte, 0), // Empty
nil, // Nil
}
plaintext := []byte("Test plaintext")
iv := make([]byte, aes.BlockSize)
_, _ = rand.Read(iv)
for _, key := range invalidKeys {
symmetricKey := &AESSymmetricKey{
Key: key,
IV: iv,
}
encrypter, err := symmetricKey.NewEncrypter()
if err == nil {
_, err = encrypter.Encrypt(plaintext)
}
if err == nil {
t.Errorf("Expected error for invalid key length %d, but got none", len(key))
} else {
t.Logf("Correctly got error for key length %d: %v", len(key), err)
}
}
}
func TestAESDecryptInvalidInput(t *testing.T) {
key := make([]byte, 32) // Valid key length for AES-256
iv := make([]byte, aes.BlockSize)
_, _ = rand.Read(key)
_, _ = rand.Read(iv)
symmetricKey := &AESSymmetricKey{
Key: key,
IV: iv,
}
decrypter, err := symmetricKey.NewDecrypter()
if err != nil {
t.Fatalf("Failed to create decrypter: %v", err)
}
invalidCiphertexts := [][]byte{
make([]byte, 15), // Not a multiple of block size
make([]byte, 0), // Empty
nil, // Nil
}
for _, ciphertext := range invalidCiphertexts {
_, err := decrypter.Decrypt(ciphertext)
if err == nil {
t.Errorf("Expected error for invalid ciphertext length %d, but got none", len(ciphertext))
} else {
t.Logf("Correctly got error for ciphertext length %d: %v", len(ciphertext), err)
}
}
}
func TestPKCS7PadUnpad(t *testing.T) {
testCases := []struct {
name string
input []byte
blockSize int
}{
{"Empty input", []byte{}, 16},
{"Exact block size", bytes.Repeat([]byte("A"), 16), 16},
{"One byte short", bytes.Repeat([]byte("A"), 15), 16},
{"Multiple blocks", bytes.Repeat([]byte("A"), 32), 16},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
padded := pkcs7Pad(tc.input, tc.blockSize)
if len(padded)%tc.blockSize != 0 {
t.Errorf("Padded data length (%d) is not a multiple of block size (%d)", len(padded), tc.blockSize)
}
unpadded, err := pkcs7Unpad(padded)
if err != nil {
t.Fatalf("Unpadding failed: %v", err)
}
if !bytes.Equal(tc.input, unpadded) {
t.Errorf("Unpadded data doesn't match original input.\nOriginal: %s\nUnpadded: %s",
hex.EncodeToString(tc.input), hex.EncodeToString(unpadded))
}
})
}
}
func TestPKCS7UnpadInvalidInput(t *testing.T) {
invalidInputs := []struct {
name string
input []byte
}{
{"Empty slice", []byte{}},
{"Invalid padding value", []byte{1, 2, 3, 4, 0}}, // Padding value 0 is invalid
{"Padding larger than block size", append(bytes.Repeat([]byte{17}, 17))}, // Padding value 17 (>16) is invalid
{"Incorrect padding bytes", []byte{1, 2, 3, 4, 5, 6, 2, 3, 3}}, // Last padding bytes do not match padding value
{"Valid block size but invalid padding", append(bytes.Repeat([]byte{1}, 15), 3)}, // Padding value 3, but bytes are 1
}
for _, tc := range invalidInputs {
t.Run(tc.name, func(t *testing.T) {
_, err := pkcs7Unpad(tc.input)
if err == nil {
t.Errorf("Expected error for invalid input %v, but got none", tc.input)
}
})
}
}

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

@@ -0,0 +1,194 @@
package crypto
import (
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"errors"
"io"
"math/big"
"github.com/sirupsen/logrus"
curve25519 "go.step.sm/crypto/x25519"
)
var Curve25519EncryptTooBig = errors.New("failed to encrypt data, too big for Curve25519")
type Curve25519PublicKey []byte
type Curve25519Verifier struct {
k []byte
}
func (k Curve25519PublicKey) NewVerifier() (v Verifier, err error) {
temp := new(Curve25519Verifier)
temp.k = k
v = temp
return temp, nil
}
func (k Curve25519PublicKey) Len() int {
length := len(k)
log.WithField("length", length).Debug("Retrieved Curve25519PublicKey length")
return length
}
func createCurve25519PublicKey(data []byte) (k *curve25519.PublicKey) {
log.WithField("data_length", len(data)).Debug("Creating Curve25519PublicKey")
if len(data) == 256 {
k2 := curve25519.PublicKey{}
copy(k2[:], data)
k = &k2
log.Debug("Curve25519PublicKey created successfully")
} else {
log.Warn("Invalid data length for Curve25519PublicKey")
}
return
}
func createCurve25519Encryption(pub *curve25519.PublicKey, rand io.Reader) (enc *Curve25519Encryption, err error) {
/*kbytes := make([]byte, 256)
k := new(big.Int)
for err == nil {
_, err = io.ReadFull(rand, kbytes)
k = new(big.Int).SetBytes(kbytes)
k = k.Mod(k, pub.P)
if k.Sign() != 0 {
break
}
}
if err == nil {
enc = &Curve25519Encryption{}
}*/
log.Warn("createCurve25519Encryption is not implemented")
return
}
type Curve25519Encryption struct {
p, a, b1 *big.Int
}
func (curve25519 *Curve25519Encryption) Encrypt(data []byte) (enc []byte, err error) {
log.WithField("data_length", len(data)).Debug("Encrypting data with Curve25519")
return curve25519.EncryptPadding(data, true)
}
func (curve25519 *Curve25519Encryption) EncryptPadding(data []byte, zeroPadding bool) (encrypted []byte, err error) {
log.WithFields(logrus.Fields{
"data_length": len(data),
"zero_padding": zeroPadding,
}).Debug("Encrypting data with padding using Curve25519")
if len(data) > 222 {
log.Error("Data too big for Curve25519 encryption")
err = Curve25519EncryptTooBig
return
}
mbytes := make([]byte, 255)
mbytes[0] = 0xFF
copy(mbytes[33:], data)
// do sha256 of payload
d := sha256.Sum256(mbytes[33 : len(data)+33])
copy(mbytes[1:], d[:])
m := new(big.Int).SetBytes(mbytes)
// do encryption
b := new(big.Int).Mod(new(big.Int).Mul(curve25519.b1, m), curve25519.p).Bytes()
if zeroPadding {
encrypted = make([]byte, 514)
copy(encrypted[1:], curve25519.a.Bytes())
copy(encrypted[258:], b)
} else {
encrypted = make([]byte, 512)
copy(encrypted, curve25519.a.Bytes())
copy(encrypted[256:], b)
}
log.WithField("encrypted_length", len(encrypted)).Debug("Data encrypted successfully")
return
}
func (elg Curve25519PublicKey) NewEncrypter() (enc Encrypter, err error) {
log.Debug("Creating new Curve25519 Encrypter")
k := createCurve25519PublicKey(elg[:])
enc, err = createCurve25519Encryption(k, rand.Reader)
if err != nil {
log.WithError(err).Error("Failed to create Curve25519 Encrypter")
} else {
log.Debug("Curve25519 Encrypter created successfully")
}
return
}
func (v *Curve25519Verifier) VerifyHash(h, sig []byte) (err error) {
log.WithFields(logrus.Fields{
"hash_length": len(h),
"signature_length": len(sig),
}).Debug("Verifying hash with Curve25519")
if len(sig) != curve25519.SignatureSize {
log.Error("Bad signature size")
err = ErrBadSignatureSize
return
}
if len(v.k) != curve25519.PublicKeySize {
log.Error("Invalid Curve25519 public key size")
err = errors.New("failed to verify: invalid curve25519 public key size")
return
}
ok := curve25519.Verify(v.k, h, sig)
if !ok {
log.Error("Invalid signature")
err = errors.New("failed to verify: invalid signature")
} else {
log.Debug("Hash verified successfully")
}
return
}
func (v *Curve25519Verifier) Verify(data, sig []byte) (err error) {
log.WithFields(logrus.Fields{
"data_length": len(data),
"signature_length": len(sig),
}).Debug("Verifying data with Curve25519")
h := sha512.Sum512(data)
err = v.VerifyHash(h[:], sig)
return
}
type Curve25519PrivateKey curve25519.PrivateKey
type Curve25519Signer struct {
k []byte
}
func (s *Curve25519Signer) Sign(data []byte) (sig []byte, err error) {
log.WithField("data_length", len(data)).Debug("Signing data with Curve25519")
if len(s.k) != curve25519.PrivateKeySize {
log.Error("Invalid Curve25519 private key size")
err = errors.New("failed to sign: invalid curve25519 private key size")
return
}
h := sha512.Sum512(data)
sig, err = s.SignHash(h[:])
if err != nil {
log.WithError(err).Error("Failed to sign data")
} else {
log.WithField("signature_length", len(sig)).Debug("Data signed successfully")
}
return
}
func (s *Curve25519Signer) SignHash(h []byte) (sig []byte, err error) {
log.WithField("hash_length", len(h)).Debug("Signing hash with Curve25519")
sig, err = curve25519.Sign(rand.Reader, s.k, h)
if err != nil {
log.WithError(err).Error("Failed to sign hash")
} else {
log.WithField("signature_length", len(sig)).Debug("Hash signed successfully")
}
// return curve25519.Sign(rand.Reader, s.k, h)
return
}

View File

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

View File

@@ -1,4 +1,2 @@
//
// package for i2p specific crpytography
//
package crypto

688
lib/crypto/doc.md Normal file
View 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

View File

@@ -6,6 +6,8 @@ import (
"crypto/sha1"
"io"
"math/big"
"github.com/sirupsen/logrus"
)
var dsap = new(big.Int).SetBytes([]byte{
@@ -43,16 +45,24 @@ var param = dsa.Parameters{
// generate a dsa keypair
func generateDSA(priv *dsa.PrivateKey, rand io.Reader) error {
log.Debug("Generating DSA key pair")
// put our paramters in
priv.P = param.P
priv.Q = param.Q
priv.G = param.G
// generate the keypair
return dsa.GenerateKey(priv, rand)
err := dsa.GenerateKey(priv, rand)
if err != nil {
log.WithError(err).Error("Failed to generate DSA key pair")
} else {
log.Debug("DSA key pair generated successfully")
}
return err
}
// create i2p dsa public key given its public component
func createDSAPublicKey(Y *big.Int) *dsa.PublicKey {
log.Debug("Creating DSA public key")
return &dsa.PublicKey{
Parameters: param,
Y: Y,
@@ -61,6 +71,7 @@ func createDSAPublicKey(Y *big.Int) *dsa.PublicKey {
// createa i2p dsa private key given its public component
func createDSAPrivkey(X *big.Int) (k *dsa.PrivateKey) {
log.Debug("Creating DSA private key")
if X.Cmp(dsap) == -1 {
Y := new(big.Int)
Y.Exp(dsag, X, dsap)
@@ -71,6 +82,9 @@ func createDSAPrivkey(X *big.Int) (k *dsa.PrivateKey) {
},
X: X,
}
log.Debug("DSA private key created successfully")
} else {
log.Warn("Failed to create DSA private key: X is not less than p")
}
return
}
@@ -83,6 +97,7 @@ type DSAPublicKey [128]byte
// create a new dsa verifier
func (k DSAPublicKey) NewVerifier() (v Verifier, err error) {
log.Debug("Creating new DSA verifier")
v = &DSAVerifier{
k: createDSAPublicKey(new(big.Int).SetBytes(k[:])),
}
@@ -91,6 +106,10 @@ func (k DSAPublicKey) NewVerifier() (v Verifier, err error) {
// verify data with a dsa public key
func (v *DSAVerifier) Verify(data, sig []byte) (err error) {
log.WithFields(logrus.Fields{
"data_length": len(data),
"sig_length": len(sig),
}).Debug("Verifying DSA signature")
h := sha1.Sum(data)
err = v.VerifyHash(h[:], sig)
return
@@ -98,16 +117,23 @@ func (v *DSAVerifier) Verify(data, sig []byte) (err error) {
// verify hash of data with a dsa public key
func (v *DSAVerifier) VerifyHash(h, sig []byte) (err error) {
log.WithFields(logrus.Fields{
"hash_length": len(h),
"sig_length": len(sig),
}).Debug("Verifying DSA signature hash")
if len(sig) == 40 {
r := new(big.Int).SetBytes(sig[:20])
s := new(big.Int).SetBytes(sig[20:])
if dsa.Verify(v.k, h, r, s) {
// valid signature
log.Debug("DSA signature verified successfully")
} else {
// invalid signature
log.Warn("Invalid DSA signature")
err = ErrInvalidSignature
}
} else {
log.Error("Bad DSA signature size")
err = ErrBadSignatureSize
}
return
@@ -125,6 +151,7 @@ type DSAPrivateKey [20]byte
// create a new dsa signer
func (k DSAPrivateKey) NewSigner() (s Signer, err error) {
log.Debug("Creating new DSA signer")
s = &DSASigner{
k: createDSAPrivkey(new(big.Int).SetBytes(k[:])),
}
@@ -134,30 +161,38 @@ func (k DSAPrivateKey) NewSigner() (s Signer, err error) {
func (k DSAPrivateKey) Public() (pk DSAPublicKey, err error) {
p := createDSAPrivkey(new(big.Int).SetBytes(k[:]))
if p == nil {
log.Error("Invalid DSA private key format")
err = ErrInvalidKeyFormat
} else {
copy(pk[:], p.Y.Bytes())
log.Debug("DSA public key derived successfully")
}
return
}
func (k DSAPrivateKey) Generate() (s DSAPrivateKey, err error) {
log.Debug("Generating new DSA private key")
dk := new(dsa.PrivateKey)
err = generateDSA(dk, rand.Reader)
if err == nil {
copy(k[:], dk.X.Bytes())
s = k
log.Debug("New DSA private key generated successfully")
} else {
log.WithError(err).Error("Failed to generate new DSA private key")
}
return
}
func (ds *DSASigner) Sign(data []byte) (sig []byte, err error) {
log.WithField("data_length", len(data)).Debug("Signing data with DSA")
h := sha1.Sum(data)
sig, err = ds.SignHash(h[:])
return
}
func (ds *DSASigner) SignHash(h []byte) (sig []byte, err error) {
log.WithField("hash_length", len(h)).Debug("Signing hash with DSA")
var r, s *big.Int
r, s, err = dsa.Sign(rand.Reader, ds.k, h)
if err == nil {
@@ -168,6 +203,9 @@ func (ds *DSASigner) SignHash(h []byte) (sig []byte, err error) {
sb := s.Bytes()
sl := len(sb)
copy(sig[20+(20-sl):], sb)
log.WithField("sig_length", len(sig)).Debug("DSA signature created successfully")
} else {
log.WithError(err).Error("Failed to create DSA signature")
}
return
}

View File

@@ -2,7 +2,6 @@ package crypto
import (
"crypto/rand"
log "github.com/sirupsen/logrus"
"io"
"testing"
)
@@ -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)
}

View File

@@ -4,6 +4,8 @@ import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"github.com/sirupsen/logrus"
)
type ECDSAVerifier struct {
@@ -14,15 +16,27 @@ type ECDSAVerifier struct {
// verify a signature given the hash
func (v *ECDSAVerifier) VerifyHash(h, sig []byte) (err error) {
log.WithFields(logrus.Fields{
"hash_length": len(h),
"sig_length": len(sig),
}).Debug("Verifying ECDSA signature hash")
r, s := elliptic.Unmarshal(v.c, sig)
if r == nil || s == nil || !ecdsa.Verify(v.k, h, r, s) {
log.Warn("Invalid ECDSA signature")
err = ErrInvalidSignature
} else {
log.Debug("ECDSA signature verified successfully")
}
return
}
// verify a block of data by hashing it and comparing the hash against the signature
func (v *ECDSAVerifier) Verify(data, sig []byte) (err error) {
log.WithFields(logrus.Fields{
"data_length": len(data),
"sig_length": len(sig),
}).Debug("Verifying ECDSA signature")
// sum the data and get the hash
h := v.h.New().Sum(data)[len(data):]
// verify
@@ -31,8 +45,13 @@ func (v *ECDSAVerifier) Verify(data, sig []byte) (err error) {
}
func createECVerifier(c elliptic.Curve, h crypto.Hash, k []byte) (ev *ECDSAVerifier, err error) {
log.WithFields(logrus.Fields{
"curve": c.Params().Name,
"hash": h.String(),
}).Debug("Creating ECDSA verifier")
x, y := elliptic.Unmarshal(c, k[:])
if x == nil {
log.Error("Invalid ECDSA key format")
err = ErrInvalidKeyFormat
} else {
ev = &ECDSAVerifier{
@@ -40,39 +59,64 @@ func createECVerifier(c elliptic.Curve, h crypto.Hash, k []byte) (ev *ECDSAVerif
h: h,
}
ev.k = &ecdsa.PublicKey{c, x, y}
log.Debug("ECDSA verifier created successfully")
}
return
}
type ECP256PublicKey [64]byte
type ECP256PrivateKey [32]byte
type (
ECP256PublicKey [64]byte
ECP256PrivateKey [32]byte
)
func (k ECP256PublicKey) Len() int {
return len(k)
}
func (k ECP256PublicKey) NewVerifier() (Verifier, error) {
return createECVerifier(elliptic.P256(), crypto.SHA256, k[:])
log.Debug("Creating new P256 ECDSA verifier")
// return createECVerifier(elliptic.P256(), crypto.SHA256, k[:])
v, err := createECVerifier(elliptic.P256(), crypto.SHA256, k[:])
if err != nil {
log.WithError(err).Error("Failed to create P256 ECDSA verifier")
}
return v, err
}
type ECP384PublicKey [96]byte
type ECP384PrivateKey [48]byte
type (
ECP384PublicKey [96]byte
ECP384PrivateKey [48]byte
)
func (k ECP384PublicKey) Len() int {
return len(k)
}
func (k ECP384PublicKey) NewVerifier() (Verifier, error) {
return createECVerifier(elliptic.P384(), crypto.SHA384, k[:])
log.Debug("Creating new P384 ECDSA verifier")
v, err := createECVerifier(elliptic.P384(), crypto.SHA384, k[:])
if err != nil {
log.WithError(err).Error("Failed to create P384 ECDSA verifier")
}
return v, err
// return createECVerifier(elliptic.P384(), crypto.SHA384, k[:])
}
type ECP521PublicKey [132]byte
type ECP521PrivateKey [66]byte
type (
ECP521PublicKey [132]byte
ECP521PrivateKey [66]byte
)
func (k ECP521PublicKey) Len() int {
return len(k)
}
func (k ECP521PublicKey) NewVerifier() (Verifier, error) {
return createECVerifier(elliptic.P521(), crypto.SHA512, k[:])
log.Debug("Creating new P521 ECDSA verifier")
v, err := createECVerifier(elliptic.P521(), crypto.SHA512, k[:])
if err != nil {
log.WithError(err).Error("Failed to create P521 ECDSA verifier")
}
return v, err
// return createECVerifier(elliptic.P521(), crypto.SHA512, k[:])
}

View File

@@ -2,10 +2,18 @@ package crypto
import (
"crypto/ed25519"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"errors"
"io"
"math/big"
"github.com/sirupsen/logrus"
)
var Ed25519EncryptTooBig = errors.New("failed to encrypt data, too big for Ed25519")
type Ed25519PublicKey []byte
type Ed25519Verifier struct {
@@ -19,24 +27,130 @@ func (k Ed25519PublicKey) NewVerifier() (v Verifier, err error) {
return temp, nil
}
func (k Ed25519PublicKey) Len() int {
return len(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
}
}
if err == nil {
enc = &Ed25519Encryption{}
}*/
log.Warn("createEd25519Encryption is not implemented")
return
}
type Ed25519Encryption struct {
p, a, b1 *big.Int
}
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
}
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(ed25519.b1, m), ed25519.p).Bytes()
if zeroPadding {
encrypted = make([]byte, 514)
copy(encrypted[1:], ed25519.a.Bytes())
copy(encrypted[258:], b)
} else {
encrypted = make([]byte, 512)
copy(encrypted, ed25519.a.Bytes())
copy(encrypted[256:], b)
}
log.WithField("encrypted_length", len(encrypted)).Debug("Data encrypted successfully with Ed25519")
return
}
func (elg Ed25519PublicKey) NewEncrypter() (enc Encrypter, err error) {
log.Debug("Creating new Ed25519 encrypter")
k := createEd25519PublicKey(elg[:])
enc, err = createEd25519Encryption(k, rand.Reader)
if err != nil {
log.WithError(err).Error("Failed to create Ed25519 encrypter")
} else {
log.Debug("Ed25519 encrypter created successfully")
}
return
}
func (v *Ed25519Verifier) VerifyHash(h, sig []byte) (err error) {
log.WithFields(logrus.Fields{
"hash_length": len(h),
"sig_length": len(sig),
}).Debug("Verifying Ed25519 signature hash")
if len(sig) != ed25519.SignatureSize {
log.Error("Bad Ed25519 signature size")
err = ErrBadSignatureSize
return
}
if len(v.k) != ed25519.PublicKeySize {
log.Error("Invalid Ed25519 public key size")
err = errors.New("failed to verify: invalid ed25519 public key size")
return
}
ok := ed25519.Verify(v.k, h, sig)
if !ok {
log.Warn("Invalid Ed25519 signature")
err = errors.New("failed to verify: invalid signature")
} else {
log.Debug("Ed25519 signature verified successfully")
}
return
}
func (v *Ed25519Verifier) Verify(data, sig []byte) (err error) {
log.WithFields(logrus.Fields{
"data_length": len(data),
"sig_length": len(sig),
}).Debug("Verifying Ed25519 signature")
h := sha512.Sum512(data)
err = v.VerifyHash(h[:], sig)
return
@@ -49,7 +163,10 @@ type Ed25519Signer struct {
}
func (s *Ed25519Signer) Sign(data []byte) (sig []byte, err error) {
log.WithField("data_length", len(data)).Debug("Signing data with Ed25519")
if len(s.k) != ed25519.PrivateKeySize {
log.Error("Invalid Ed25519 private key size")
err = errors.New("failed to sign: invalid ed25519 private key size")
return
}
@@ -59,6 +176,8 @@ func (s *Ed25519Signer) Sign(data []byte) (sig []byte, err error) {
}
func (s *Ed25519Signer) SignHash(h []byte) (sig []byte, err error) {
log.WithField("hash_length", len(h)).Debug("Signing hash with Ed25519")
sig = ed25519.Sign(s.k, h)
log.WithField("signature_length", len(sig)).Debug("Ed25519 signature created successfully")
return
}

View File

@@ -5,9 +5,12 @@ import (
"crypto/sha256"
"crypto/subtle"
"errors"
"golang.org/x/crypto/openpgp/elgamal"
"io"
"math/big"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/openpgp/elgamal"
)
var elgp = new(big.Int).SetBytes([]byte{
@@ -29,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)
@@ -46,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
}
@@ -55,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
@@ -82,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)
@@ -102,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
@@ -129,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)
@@ -157,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 {
@@ -179,20 +221,31 @@ func createElgamalEncryption(pub *elgamal.PublicKey, rand io.Reader) (enc *Elgam
a: new(big.Int).Exp(pub.G, k, pub.P),
b1: new(big.Int).Exp(pub.Y, k, pub.P),
}
log.Debug("ElGamal encryption session created successfully")
} else {
log.WithError(err).Error("Failed to create ElGamal encryption session")
}
return
}
type ElgPublicKey [256]byte
type ElgPrivateKey [256]byte
type (
ElgPublicKey [256]byte
ElgPrivateKey [256]byte
)
func (elg ElgPublicKey) Len() int {
return len(elg)
}
func (elg ElgPublicKey) NewEncrypter() (enc Encrypter, err error) {
log.Debug("Creating new ElGamal encrypter")
k := createElgamalPublicKey(elg[:])
enc, err = createElgamalEncryption(k, rand.Reader)
if err != nil {
log.WithError(err).Error("Failed to create ElGamal encrypter")
} else {
log.Debug("ElGamal encrypter created successfully")
}
return
}
@@ -201,8 +254,10 @@ func (elg ElgPrivateKey) Len() int {
}
func (elg ElgPrivateKey) NewDecrypter() (dec Decrypter, err error) {
log.Debug("Creating new ElGamal decrypter")
dec = &elgDecrypter{
k: createElgamalPrivateKey(elg[:]),
}
log.Debug("ElGamal decrypter created successfully")
return
}

View File

@@ -3,10 +3,10 @@ package crypto
import (
"bytes"
"crypto/rand"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/openpgp/elgamal"
"io"
"testing"
"golang.org/x/crypto/openpgp/elgamal"
)
func BenchmarkElgGenerate(b *testing.B) {
@@ -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) {

View File

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

View File

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

View File

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

View File

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

View File

@@ -19,7 +19,7 @@ type Tunnel struct {
}
func NewTunnelCrypto(layerKey, ivKey TunnelKey) (t *Tunnel, err error) {
log.Debug("Creating new Tunnel crypto")
t = new(Tunnel)
t.layerKey, err = aes.NewCipher(layerKey[:])
if err == nil {
@@ -28,24 +28,31 @@ func NewTunnelCrypto(layerKey, ivKey TunnelKey) (t *Tunnel, err error) {
if err != nil {
// error happened we don't need t
// log.WithError(err).Error("Failed to create Tunnel crypto")
t = nil
} else {
log.Debug("Tunnel crypto created successfully")
}
return
}
// encrypt tunnel data in place
func (t *Tunnel) Encrypt(td *TunnelData) {
log.Debug("Encrypting Tunnel data")
data := *td
t.ivKey.Encrypt(data[16:1024], data[16:1024])
layerBlock := cipher.NewCBCEncrypter(t.layerKey, data[:16])
layerBlock.CryptBlocks(data[16:1024], data[16:1024])
t.ivKey.Encrypt(data[16:1024], data[16:1024])
log.Debug("Tunnel data encrypted successfully")
}
func (t *Tunnel) Decrypt(td *TunnelData) {
log.Debug("Decrypting Tunnel data")
data := *td
t.ivKey.Decrypt(data[16:1024], data[16:1024])
layerBlock := cipher.NewCBCDecrypter(t.layerKey, data[:16])
layerBlock.CryptBlocks(data[16:1024], data[16:1024])
t.ivKey.Decrypt(data[16:1024], data[16:1024])
log.Debug("Tunnel data decrypted successfully")
}

View File

@@ -4,12 +4,16 @@ import (
"errors"
"time"
"github.com/sirupsen/logrus"
common "github.com/go-i2p/go-i2p/lib/common/data"
"github.com/go-i2p/go-i2p/lib/common/session_key"
"github.com/go-i2p/go-i2p/lib/tunnel"
log "github.com/sirupsen/logrus"
"github.com/go-i2p/go-i2p/lib/util/logger"
)
var log = logger.GetGoI2PLogger()
/*
I2P I2NP BuildRequestRecord
https://geti2p.net/spec/i2np
@@ -149,8 +153,10 @@ padding :: Data
total length: 222
*/
type BuildRequestRecordElGamalAES [528]byte
type BuildRequestRecordElGamal [528]byte
type (
BuildRequestRecordElGamalAES [528]byte
BuildRequestRecordElGamal [528]byte
)
type BuildRequestRecord struct {
ReceiveTunnel tunnel.TunnelID
@@ -170,80 +176,94 @@ type BuildRequestRecord struct {
var ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA = errors.New("not enough i2np build request record data")
func ReadBuildRequestRecord(data []byte) (BuildRequestRecord, error) {
log.Debug("Reading BuildRequestRecord")
build_request_record := BuildRequestRecord{}
receive_tunnel, err := readBuildRequestRecordReceiveTunnel(data)
if err != nil {
log.WithError(err).Error("Failed to read ReceiveTunnel")
return build_request_record, err
}
build_request_record.ReceiveTunnel = receive_tunnel
our_ident, err := readBuildRequestRecordOurIdent(data)
if err != nil {
log.WithError(err).Error("Failed to read OurIdent")
return build_request_record, err
}
build_request_record.OurIdent = our_ident
next_tunnel, err := readBuildRequestRecordNextTunnel(data)
if err != nil {
log.WithError(err).Error("Failed to read NextTunnel")
return build_request_record, err
}
build_request_record.NextTunnel = next_tunnel
next_ident, err := readBuildRequestRecordNextIdent(data)
if err != nil {
log.WithError(err).Error("Failed to read NextIdent")
return build_request_record, err
}
build_request_record.NextIdent = next_ident
layer_key, err := readBuildRequestRecordLayerKey(data)
if err != nil {
log.WithError(err).Error("Failed to read LayerKey")
return build_request_record, err
}
build_request_record.LayerKey = layer_key
iv_key, err := readBuildRequestRecordIVKey(data)
if err != nil {
log.WithError(err).Error("Failed to read IVKey")
return build_request_record, err
}
build_request_record.IVKey = iv_key
reply_key, err := readBuildRequestRecordReplyKey(data)
if err != nil {
log.WithError(err).Error("Failed to read ReplyKey")
return build_request_record, err
}
build_request_record.ReplyKey = reply_key
reply_iv, err := readBuildRequestRecordReplyIV(data)
if err != nil {
log.WithError(err).Error("Failed to read ReplyIV")
return build_request_record, err
}
build_request_record.ReplyIV = reply_iv
flag, err := readBuildRequestRecordFlag(data)
if err != nil {
log.WithError(err).Error("Failed to read Flag")
return build_request_record, err
}
build_request_record.Flag = flag
request_time, err := readBuildRequestRecordRequestTime(data)
if err != nil {
log.WithError(err).Error("Failed to read RequestTime")
return build_request_record, err
}
build_request_record.RequestTime = request_time
send_message_id, err := readBuildRequestRecordSendMessageID(data)
if err != nil {
log.WithError(err).Error("Failed to read SendMessageID")
return build_request_record, err
}
build_request_record.SendMessageID = send_message_id
padding, err := readBuildRequestRecordPadding(data)
if err != nil {
log.WithError(err).Error("Failed to read Padding")
return build_request_record, err
}
build_request_record.Padding = padding
log.Debug("BuildRequestRecord read successfully")
return build_request_record, nil
}
@@ -256,7 +276,7 @@ func readBuildRequestRecordReceiveTunnel(data []byte) (tunnel.TunnelID, error) {
common.Integer(data[0:4]).Int(),
)
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordReceiveTunnel",
"receieve_tunnel": receive_tunnel,
}).Debug("parsed_build_request_record_receive_tunnel")
@@ -271,7 +291,7 @@ func readBuildRequestRecordOurIdent(data []byte) (common.Hash, error) {
hash := common.Hash{}
copy(hash[:], data[4:36])
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordOurIdent",
}).Debug("parsed_build_request_record_our_ident")
return hash, nil
@@ -286,7 +306,7 @@ func readBuildRequestRecordNextTunnel(data []byte) (tunnel.TunnelID, error) {
common.Integer(data[36:40]).Int(),
)
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordNextTunnel",
"next_tunnel": next_tunnel,
}).Debug("parsed_build_request_record_next_tunnel")
@@ -301,7 +321,7 @@ func readBuildRequestRecordNextIdent(data []byte) (common.Hash, error) {
hash := common.Hash{}
copy(hash[:], data[40:72])
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordNextIdent",
}).Debug("parsed_build_request_record_next_ident")
return hash, nil
@@ -315,7 +335,7 @@ func readBuildRequestRecordLayerKey(data []byte) (session_key.SessionKey, error)
session_key := session_key.SessionKey{}
copy(session_key[:], data[72:104])
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordLayerKey",
}).Debug("parsed_build_request_record_layer_key")
return session_key, nil
@@ -329,7 +349,7 @@ func readBuildRequestRecordIVKey(data []byte) (session_key.SessionKey, error) {
session_key := session_key.SessionKey{}
copy(session_key[:], data[104:136])
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordIVKey",
}).Debug("parsed_build_request_record_iv_key")
return session_key, nil
@@ -343,7 +363,7 @@ func readBuildRequestRecordReplyKey(data []byte) (session_key.SessionKey, error)
session_key := session_key.SessionKey{}
copy(session_key[:], data[136:168])
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordReplyKey",
}).Debug("parsed_build_request_record_reply_key")
return session_key, nil
@@ -357,7 +377,7 @@ func readBuildRequestRecordReplyIV(data []byte) ([16]byte, error) {
iv := [16]byte{}
copy(iv[:], data[168:184])
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordReplyIV",
}).Debug("parsed_build_request_record_reply_iv")
return iv, nil
@@ -370,7 +390,7 @@ func readBuildRequestRecordFlag(data []byte) (int, error) {
flag := common.Integer([]byte{data[185]}).Int()
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordFlag",
"flag": flag,
}).Debug("parsed_build_request_record_flag")
@@ -385,7 +405,7 @@ func readBuildRequestRecordRequestTime(data []byte) (time.Time, error) {
count := common.Integer(data[185:189]).Int()
rtime := time.Unix(0, 0).Add(time.Duration(count) * time.Hour)
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordRequestTime",
}).Debug("parsed_build_request_record_request_time")
return rtime, nil
@@ -398,7 +418,7 @@ func readBuildRequestRecordSendMessageID(data []byte) (int, error) {
send_message_id := common.Integer(data[189:193]).Int()
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordSendMessageID",
}).Debug("parsed_build_request_record_send_message_id")
return send_message_id, nil
@@ -412,7 +432,7 @@ func readBuildRequestRecordPadding(data []byte) ([29]byte, error) {
padding := [29]byte{}
copy(padding[:], data[193:222])
log.WithFields(log.Fields{
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordPadding",
}).Debug("parsed_build_request_record_padding")
return padding, nil

View File

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

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