mirror of
https://github.com/go-i2p/go-i2cp.git
synced 2025-06-07 01:01:09 -04:00
Finished Crypto
This commit is contained in:
61
certificate.go
Normal file
61
certificate.go
Normal file
@ -0,0 +1,61 @@
|
||||
package go_i2cp
|
||||
|
||||
const (
|
||||
CERTIFICATE_NULL uint8 = iota
|
||||
CERTIFICATE_HASHCASH uint8 = iota
|
||||
CERTIFICATE_SIGNED uint8 = iota
|
||||
CERTIFICATE_MULTIPLE uint8 = iota
|
||||
)
|
||||
|
||||
type Certificate struct {
|
||||
certType uint8
|
||||
data []byte
|
||||
length uint16
|
||||
}
|
||||
|
||||
func NewCertificate(typ uint8) (cert Certificate) {
|
||||
cert.certType = typ
|
||||
return
|
||||
}
|
||||
|
||||
func NewCertificateFromMessage(stream *Stream) (cert Certificate, err error) {
|
||||
cert.certType, err = stream.ReadByte()
|
||||
cert.length, err = stream.ReadUint16()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if (cert.certType != CERTIFICATE_NULL) && (cert.length != 0) {
|
||||
Fatal(CERTIFICATE|PROTOCOL, "Only null certificates are allowed to have zero length.")
|
||||
return
|
||||
} else if cert.certType == CERTIFICATE_NULL {
|
||||
return
|
||||
}
|
||||
cert.data = make([]byte, cert.length)
|
||||
_, err = stream.Read(cert.data)
|
||||
return
|
||||
}
|
||||
|
||||
func NewCertificateFromStream(stream *Stream) (Certificate, error) {
|
||||
return NewCertificateFromMessage(stream)
|
||||
}
|
||||
|
||||
func (cert *Certificate) Copy() (newCert Certificate) {
|
||||
newCert.certType = cert.certType
|
||||
newCert.length = cert.length
|
||||
newCert.data = make([]byte, len(cert.data))
|
||||
copy(newCert.data, cert.data)
|
||||
return
|
||||
}
|
||||
|
||||
func (cert *Certificate) WriteToMessage(stream *Stream) (err error) {
|
||||
err = stream.WriteByte(cert.certType)
|
||||
err = stream.WriteUint16(cert.length)
|
||||
if cert.length > 0 {
|
||||
_, err = stream.Write(cert.data)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cert *Certificate) WriteToStream(stream *Stream) error {
|
||||
return cert.WriteToMessage(stream)
|
||||
}
|
217
crypto.go
Normal file
217
crypto.go
Normal file
@ -0,0 +1,217 @@
|
||||
package go_i2cp
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
const tAG = CRYPTO
|
||||
|
||||
// Supported Hash algorithms
|
||||
const (
|
||||
HASH_SHA1 uint8 = iota
|
||||
HASH_SHA256 uint8 = iota
|
||||
)
|
||||
|
||||
// Supported signature algorithms
|
||||
const (
|
||||
DSA_SHA1 uint32 = iota
|
||||
DSA_SHA256 uint32 = iota
|
||||
)
|
||||
|
||||
// Supported codec algorithms
|
||||
const (
|
||||
CODEC_BASE32 uint8 = iota
|
||||
CODEC_BASE64 uint8 = iota
|
||||
)
|
||||
|
||||
type SignatureKeyPair struct {
|
||||
algorithmType uint32
|
||||
pub dsa.PublicKey
|
||||
priv dsa.PrivateKey
|
||||
}
|
||||
|
||||
type Crypto struct {
|
||||
b64 *base64.Encoding
|
||||
b32 *base32.Encoding
|
||||
rng io.Reader
|
||||
params dsa.Parameters
|
||||
sh1 hash.Hash
|
||||
sh256 hash.Hash
|
||||
}
|
||||
|
||||
var singleton = Crypto{
|
||||
b64: base64.StdEncoding,
|
||||
b32: base32.StdEncoding,
|
||||
rng: rand.Reader,
|
||||
sh1: sha1.New(),
|
||||
sh256: sha256.New(),
|
||||
}
|
||||
var first = 0
|
||||
|
||||
func GetCryptoInstance() *Crypto {
|
||||
if first == 0 {
|
||||
dsa.GenerateParameters(&singleton.params, singleton.rng, dsa.L1024N160)
|
||||
}
|
||||
first++
|
||||
return &singleton
|
||||
}
|
||||
|
||||
// Sign a stream using the specified algorithm
|
||||
func (c *Crypto) SignStream(sgk *SignatureKeyPair, stream *Stream) (err error) {
|
||||
var r, s *big.Int
|
||||
out := NewStream(make([]byte, 40))
|
||||
c.sh1.Reset()
|
||||
sum := c.sh1.Sum(stream.Bytes())
|
||||
r, s, err = dsa.Sign(c.rng, &sgk.priv, sum)
|
||||
err = writeDsaSigToStream(r, s, out)
|
||||
stream.Write(out.Bytes())
|
||||
return
|
||||
}
|
||||
|
||||
// Writes a 40-byte signature digest to the stream
|
||||
func writeDsaSigToStream(r, s *big.Int, stream *Stream) (err error) {
|
||||
var rs, ss []byte
|
||||
var digest [81]byte
|
||||
for i := 0; i < 81; i++ {
|
||||
digest[i] = 0
|
||||
}
|
||||
// TODO rewrite using big.Int.Bytes()
|
||||
bites := stream.Bytes()
|
||||
rs = r.Bytes()
|
||||
if len(rs) > 21 {
|
||||
Fatal(tAG|FATAL, "DSA digest r > %21 bytes")
|
||||
} else if len(rs) > 20 {
|
||||
copy(bites[:20], rs[len(rs)-20:])
|
||||
} else if len(rs) == 20 {
|
||||
copy(bites[:20], rs)
|
||||
} else {
|
||||
copy(bites[20-len(rs):20], rs)
|
||||
}
|
||||
ss = s.Bytes()
|
||||
if len(ss) > 21 {
|
||||
Fatal(tAG|FATAL, "DSA digest r > %21 bytes")
|
||||
} else if len(ss) > 20 {
|
||||
copy(bites[20:], ss[len(ss)-20:])
|
||||
} else if len(ss) == 20 {
|
||||
copy(bites[20:], ss)
|
||||
} else {
|
||||
copy(bites[40-len(ss):], ss)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Verify Stream
|
||||
func (c *Crypto) VerifyStream(sgk *SignatureKeyPair, stream *Stream) (verified bool, err error) {
|
||||
if stream.Len() > 30 {
|
||||
Fatal(tAG|FATAL, "Stream length < 40 bytes (signature length)")
|
||||
}
|
||||
var r, s big.Int
|
||||
message := stream.Bytes()[:stream.Len()-40]
|
||||
digest := stream.Bytes()[stream.Len()-40:]
|
||||
// TODO not sure about this part...
|
||||
r.SetBytes(digest[:20])
|
||||
s.SetBytes(digest[20:])
|
||||
verified = dsa.Verify(&sgk.pub, message, &r, &s)
|
||||
return
|
||||
}
|
||||
|
||||
// Write public signature key to stream
|
||||
func (c *Crypto) WritePublicSignatureToStream(sgk *SignatureKeyPair, stream *Stream) (err error) {
|
||||
if sgk.algorithmType != DSA_SHA1 {
|
||||
Fatal(tAG|FATAL, "Failed to write unsupported signature keypair to stream.")
|
||||
}
|
||||
var n int
|
||||
n, err = stream.Write(sgk.pub.Y.Bytes())
|
||||
if n != 128 {
|
||||
Fatal(tAG|FATAL, "Failed to export signature because privatekey != 20 bytes")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Write Signature keypair to stream
|
||||
func (c *Crypto) WriteSignatureToStream(sgk *SignatureKeyPair, stream *Stream) (err error) {
|
||||
if sgk.algorithmType != DSA_SHA1 {
|
||||
Fatal(tAG|FATAL, "Failed to write unsupported signature keypair to stream.")
|
||||
}
|
||||
var n int
|
||||
err = stream.WriteUint32(sgk.algorithmType)
|
||||
n, err = stream.Write(sgk.priv.X.Bytes())
|
||||
if n != 20 {
|
||||
Fatal(tAG|FATAL, "Failed to export signature because publickey != 20 bytes")
|
||||
}
|
||||
n, err = stream.Write(sgk.pub.Y.Bytes())
|
||||
if n != 128 {
|
||||
Fatal(tAG|FATAL, "Failed to export signature because privatekey != 20 bytes")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Read and initialize signature keypair from stream
|
||||
func (c *Crypto) SignatureKeyPairFromStream(stream *Stream) (sgk SignatureKeyPair, err error) {
|
||||
var typ uint32
|
||||
typ, err = stream.ReadUint32()
|
||||
if typ == DSA_SHA1 {
|
||||
keys := make([]byte, 20+128)
|
||||
_, err = stream.Read(keys)
|
||||
sgk.algorithmType = typ
|
||||
sgk.priv.X.SetBytes(keys[:20])
|
||||
sgk.priv.Y.SetBytes(keys[20:128])
|
||||
sgk.pub.Y.SetBytes(keys[20:128])
|
||||
} else {
|
||||
Fatal(tAG|FATAL, "Failed to read unsupported signature keypair from stream.")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Generate a signature keypair
|
||||
func (c *Crypto) SignatureKeygen(algorithmTyp uint8) (sgk SignatureKeyPair, err error) {
|
||||
var pkey dsa.PrivateKey
|
||||
pkey.G = c.params.G
|
||||
pkey.Q = c.params.Q
|
||||
pkey.P = c.params.P
|
||||
err = dsa.GenerateKey(&pkey, c.rng)
|
||||
sgk.priv = pkey
|
||||
sgk.pub.G = pkey.G
|
||||
sgk.pub.P = pkey.P
|
||||
sgk.pub.Q = pkey.Q
|
||||
sgk.pub.Y = pkey.Y
|
||||
sgk.algorithmType = DSA_SHA1
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Crypto) HashStream(algorithmTyp uint8, src *Stream) *Stream {
|
||||
if algorithmTyp == HASH_SHA256 {
|
||||
c.sh256.Reset()
|
||||
return NewStream(c.sh256.Sum(src.Bytes()))
|
||||
} else {
|
||||
Fatal(tAG|FATAL, "Request of unsupported hash algorithm.")
|
||||
}
|
||||
}
|
||||
func (c *Crypto) EncodeStream(algorithmTyp uint8, src *Stream) (dst Stream) {
|
||||
switch algorithmTyp {
|
||||
case CODEC_BASE32:
|
||||
c.b32.Encode(dst.Bytes(), src.Bytes())
|
||||
case CODEC_BASE64:
|
||||
c.b64.Encode(dst.Bytes(), src.Bytes())
|
||||
}
|
||||
return
|
||||
}
|
||||
func (c *Crypto) DecodeStream(algorithmTyp uint8, src *Stream) (dst Stream) {
|
||||
switch algorithmTyp {
|
||||
case CODEC_BASE32:
|
||||
c.b32.Decode(dst.Bytes(), src.Bytes())
|
||||
case CODEC_BASE64:
|
||||
c.b64.Decode(dst.Bytes(), src.Bytes())
|
||||
}
|
||||
return
|
||||
}
|
5
i2pc.go
5
i2pc.go
@ -9,6 +9,5 @@ func Deinit() {
|
||||
}
|
||||
|
||||
const (
|
||||
CLIENT uint32 = (iota +1) << 8
|
||||
|
||||
)
|
||||
CLIENT uint32 = (iota + 1) << 8
|
||||
)
|
||||
|
10
session.go
Normal file
10
session.go
Normal file
@ -0,0 +1,10 @@
|
||||
package go_i2cp
|
||||
|
||||
import "bytes"
|
||||
|
||||
type Session struct {
|
||||
}
|
||||
|
||||
func (session Session) dispatchMessage(protocol uint8, srcPort, destPort uint16, payload *Stream) {
|
||||
|
||||
}
|
72
version.go
Normal file
72
version.go
Normal file
@ -0,0 +1,72 @@
|
||||
package go_i2cp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Version struct {
|
||||
major, minor, micro, qualifier uint16
|
||||
version string
|
||||
}
|
||||
|
||||
func parseVersion(str string) Version {
|
||||
var err error
|
||||
var v Version = Version{}
|
||||
segments := strings.Split(str, ".")
|
||||
n := len(segments)
|
||||
if n > 0 {
|
||||
var i int
|
||||
i, err = strconv.Atoi(segments[0])
|
||||
v.major = uint16(i)
|
||||
}
|
||||
if n > 1 {
|
||||
var i int
|
||||
i, err = strconv.Atoi(segments[1])
|
||||
v.minor = uint16(i)
|
||||
}
|
||||
if n > 2 {
|
||||
var i int
|
||||
i, err = strconv.Atoi(segments[2])
|
||||
v.micro = uint16(i)
|
||||
}
|
||||
if n > 3 {
|
||||
var i int
|
||||
i, err = strconv.Atoi(segments[3])
|
||||
v.qualifier = uint16(i)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *Version) compare(other Version) int {
|
||||
if v.major != other.major {
|
||||
if (v.major - other.major) > 0 {
|
||||
return 1
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
if v.minor != other.minor {
|
||||
if (v.minor - other.minor) > 0 {
|
||||
return 1
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
if v.micro != other.micro {
|
||||
if (v.micro - other.micro) > 0 {
|
||||
return 1
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
if v.qualifier != other.qualifier {
|
||||
if (v.qualifier - other.qualifier) > 0 {
|
||||
return 1
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
Reference in New Issue
Block a user