Files
Go_I2p/lib/i2np/build_request_record.go

440 lines
12 KiB
Go

package i2np
import (
"time"
"github.com/samber/oops"
"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"
"github.com/go-i2p/logger"
)
var log = logger.GetGoI2PLogger()
/*
I2P I2NP BuildRequestRecord
https://geti2p.net/spec/i2np
Accurate for version 0.9.28
ElGamal and AES encrypted:
+----+----+----+----+----+----+----+----+
| encrypted data... |
~ ~
| |
+----+----+----+----+----+----+----+----+
encrypted_data :: ElGamal and AES encrypted data
length -> 528
total length: 528
ElGamal encrypted:
+----+----+----+----+----+----+----+----+
| toPeer |
+ +
| |
+----+----+----+----+----+----+----+----+
| encrypted data... |
~ ~
| |
+----+----+----+----+----+----+----+----+
toPeer :: First 16 bytes of the SHA-256 Hash of the peer's RouterIdentity
length -> 16 bytes
encrypted_data :: ElGamal-2048 encrypted data (see notes)
length -> 512
total length: 528
Cleartext:
+----+----+----+----+----+----+----+----+
| receive_tunnel | our_ident |
+----+----+----+----+ +
| |
+ +
| |
+ +
| |
+ +----+----+----+----+
| | next_tunnel |
+----+----+----+----+----+----+----+----+
| next_ident |
+ +
| |
+ +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| layer_key |
+ +
| |
+ +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| iv_key |
+ +
| |
+ +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| reply_key |
+ +
| |
+ +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| reply_iv |
+ +
| |
+----+----+----+----+----+----+----+----+
|flag| request_time | send_msg_id
+----+----+----+----+----+----+----+----+
| |
+----+ +
| 29 bytes padding |
+ +
| |
+ +----+----+
| |
+----+----+----+----+----+----+
receive_tunnel :: TunnelId
length -> 4 bytes
our_ident :: Hash
length -> 32 bytes
next_tunnel :: TunnelId
length -> 4 bytes
next_ident :: Hash
length -> 32 bytes
layer_key :: SessionKey
length -> 32 bytes
iv_key :: SessionKey
length -> 32 bytes
reply_key :: SessionKey
length -> 32 bytes
reply_iv :: data
length -> 16 bytes
flag :: Integer
length -> 1 byte
request_time :: Integer
length -> 4 bytes
Hours since the epoch, i.e. current time / 3600
send_message_id :: Integer
length -> 4 bytes
padding :: Data
length -> 29 bytes
source -> random
total length: 222
*/
type (
BuildRequestRecordElGamalAES [528]byte
BuildRequestRecordElGamal [528]byte
)
type BuildRequestRecord struct {
ReceiveTunnel tunnel.TunnelID
OurIdent common.Hash
NextTunnel tunnel.TunnelID
NextIdent common.Hash
LayerKey session_key.SessionKey
IVKey session_key.SessionKey
ReplyKey session_key.SessionKey
ReplyIV [16]byte
Flag int
RequestTime time.Time
SendMessageID int
Padding [29]byte
}
var ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA = oops.Errorf("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
}
func readBuildRequestRecordReceiveTunnel(data []byte) (tunnel.TunnelID, error) {
if len(data) < 4 {
return 0, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
}
receive_tunnel := tunnel.TunnelID(
common.Integer(data[0:4]).Int(),
)
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordReceiveTunnel",
"receieve_tunnel": receive_tunnel,
}).Debug("parsed_build_request_record_receive_tunnel")
return receive_tunnel, nil
}
func readBuildRequestRecordOurIdent(data []byte) (common.Hash, error) {
if len(data) < 36 {
return common.Hash{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
}
hash := common.Hash{}
copy(hash[:], data[4:36])
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordOurIdent",
}).Debug("parsed_build_request_record_our_ident")
return hash, nil
}
func readBuildRequestRecordNextTunnel(data []byte) (tunnel.TunnelID, error) {
if len(data) < 40 {
return 0, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
}
next_tunnel := tunnel.TunnelID(
common.Integer(data[36:40]).Int(),
)
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordNextTunnel",
"next_tunnel": next_tunnel,
}).Debug("parsed_build_request_record_next_tunnel")
return next_tunnel, nil
}
func readBuildRequestRecordNextIdent(data []byte) (common.Hash, error) {
if len(data) < 72 {
return common.Hash{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
}
hash := common.Hash{}
copy(hash[:], data[40:72])
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordNextIdent",
}).Debug("parsed_build_request_record_next_ident")
return hash, nil
}
func readBuildRequestRecordLayerKey(data []byte) (session_key.SessionKey, error) {
if len(data) < 104 {
return session_key.SessionKey{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
}
session_key := session_key.SessionKey{}
copy(session_key[:], data[72:104])
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordLayerKey",
}).Debug("parsed_build_request_record_layer_key")
return session_key, nil
}
func readBuildRequestRecordIVKey(data []byte) (session_key.SessionKey, error) {
if len(data) < 136 {
return session_key.SessionKey{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
}
session_key := session_key.SessionKey{}
copy(session_key[:], data[104:136])
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordIVKey",
}).Debug("parsed_build_request_record_iv_key")
return session_key, nil
}
func readBuildRequestRecordReplyKey(data []byte) (session_key.SessionKey, error) {
if len(data) < 168 {
return session_key.SessionKey{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
}
session_key := session_key.SessionKey{}
copy(session_key[:], data[136:168])
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordReplyKey",
}).Debug("parsed_build_request_record_reply_key")
return session_key, nil
}
func readBuildRequestRecordReplyIV(data []byte) ([16]byte, error) {
if len(data) < 184 {
return [16]byte{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
}
iv := [16]byte{}
copy(iv[:], data[168:184])
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordReplyIV",
}).Debug("parsed_build_request_record_reply_iv")
return iv, nil
}
func readBuildRequestRecordFlag(data []byte) (int, error) {
if len(data) < 185 {
return 0, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
}
flag := common.Integer([]byte{data[185]}).Int()
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordFlag",
"flag": flag,
}).Debug("parsed_build_request_record_flag")
return flag, nil
}
func readBuildRequestRecordRequestTime(data []byte) (time.Time, error) {
if len(data) < 189 {
return time.Time{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
}
count := common.Integer(data[185:189]).Int()
rtime := time.Unix(0, 0).Add(time.Duration(count) * time.Hour)
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordRequestTime",
}).Debug("parsed_build_request_record_request_time")
return rtime, nil
}
func readBuildRequestRecordSendMessageID(data []byte) (int, error) {
if len(data) < 193 {
return 0, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
}
send_message_id := common.Integer(data[189:193]).Int()
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordSendMessageID",
}).Debug("parsed_build_request_record_send_message_id")
return send_message_id, nil
}
func readBuildRequestRecordPadding(data []byte) ([29]byte, error) {
if len(data) < 222 {
return [29]byte{}, ERR_BUILD_REQUEST_RECORD_NOT_ENOUGH_DATA
}
padding := [29]byte{}
copy(padding[:], data[193:222])
log.WithFields(logrus.Fields{
"at": "i2np.readBuildRequestRecordPadding",
}).Debug("parsed_build_request_record_padding")
return padding, nil
}