Files
go-i2cp/destination.go
2018-03-12 19:46:44 -04:00

171 lines
4.6 KiB
Go

package go_i2cp
import (
"errors"
"fmt"
"math/big"
"os"
"strings"
)
const tag = DESTINATION
const PUB_KEY_SIZE = 256
const DIGEST_SIZE = 40
const DEST_SIZE = 4096
type Destination struct {
cert *Certificate
sgk SignatureKeyPair
signPubKey *big.Int
pubKey [PUB_KEY_SIZE]byte
digest [DIGEST_SIZE]byte
b32 string
b64 string
}
func NewDestination() (dest *Destination, err error) {
dest = &Destination{}
nullCert := NewCertificate(CERTIFICATE_NULL)
dest.cert = &nullCert
dest.sgk, err = GetCryptoInstance().SignatureKeygen(DSA_SHA1)
dest.signPubKey = dest.sgk.pub.Y
dest.generateB32()
dest.generateB64()
return
}
func NewDestinationFromMessage(stream *Stream) (dest *Destination, err error) {
dest = &Destination{}
_, err = stream.Read(dest.pubKey[:])
if err != nil {
return
}
dest.signPubKey, err = GetCryptoInstance().PublicKeyFromStream(DSA_SHA1, stream)
if err != nil {
return
}
dest.sgk = SignatureKeyPair{}
dest.sgk.priv.Y = dest.signPubKey
dest.sgk.pub.Y = dest.signPubKey
var cert Certificate
cert, err = NewCertificateFromMessage(stream)
if err != nil {
return
}
dest.cert = &cert
dest.generateB32()
dest.generateB64()
return dest, err
}
func NewDestinationFromStream(stream *Stream) (dest *Destination, err error) {
var cert Certificate
var pubKeyLen uint16
dest = &Destination{}
cert, err = NewCertificateFromStream(stream)
dest.cert = &cert
dest.sgk, err = GetCryptoInstance().SignatureKeyPairFromStream(stream)
pubKeyLen, err = stream.ReadUint16()
if pubKeyLen != PUB_KEY_SIZE {
Fatal(tag, "Failed to load pub key len, %d != %d", pubKeyLen, PUB_KEY_SIZE)
}
_, err = stream.Read(dest.pubKey[:])
dest.generateB32()
dest.generateB64()
return
}
func NewDestinationFromBase64(base64 string) (dest *Destination, err error) {
/* Same as decode, except from a filesystem / URL friendly set of characters,
* replacing / with ~, and + with -
*/
// see https://javadoc.freenetproject.org/freenet/support/Base64.html
if len(base64) == 0 {
err = errors.New("empty string")
return
}
var replaced string
// Convert from freenet to standard
replaced = strings.Replace(base64, "~", "/", -1)
replaced = strings.Replace(replaced, "-", "+", -1)
stream := NewStream([]byte(replaced))
var decoded *Stream
decoded, err = GetCryptoInstance().DecodeStream(CODEC_BASE64, stream)
return NewDestinationFromMessage(decoded)
}
func NewDestinationFromFile(file *os.File) (*Destination, error) {
var stream Stream
stream.loadFile(file)
return NewDestinationFromStream(&stream)
}
func (dest *Destination) Copy() (newDest Destination) {
newDest.cert = dest.cert
newDest.signPubKey = dest.signPubKey
newDest.pubKey = dest.pubKey
newDest.sgk = dest.sgk
newDest.b32 = dest.b32
newDest.b64 = dest.b64
newDest.digest = dest.digest
return
}
func (dest *Destination) WriteToFile(filename string) (err error) {
stream := NewStream(make([]byte, 0, DEST_SIZE))
dest.WriteToStream(stream)
var file *os.File
file, err = os.Open(filename)
stream.WriteTo(file)
file.Close()
return
}
func (dest *Destination) WriteToMessage(stream *Stream) (err error) {
lena := len(dest.pubKey)
_ = lena
_, err = stream.Write(dest.pubKey[:])
_, err = stream.Write(dest.signPubKey.Bytes()) //GetCryptoInstance().WriteSignatureToStream(&dest.sgk, stream)
err = dest.cert.WriteToMessage(stream)
lenb := stream.Len()
_ = lenb
return
}
func (dest *Destination) WriteToStream(stream *Stream) (err error) {
err = dest.cert.WriteToStream(stream)
err = GetCryptoInstance().WriteSignatureToStream(&dest.sgk, stream)
err = stream.WriteUint16(PUB_KEY_SIZE)
_, err = stream.Write(dest.pubKey[:])
return
}
//Doesn't seem to be used anywhere??
func (dest *Destination) Verify() (verified bool, err error) {
stream := NewStream(make([]byte, 0, DEST_SIZE))
dest.WriteToMessage(stream)
stream.Write(dest.digest[:])
return GetCryptoInstance().VerifyStream(&dest.sgk, stream)
}
func (dest *Destination) generateB32() {
stream := NewStream(make([]byte, 0, DEST_SIZE))
dest.WriteToMessage(stream)
cpt := GetCryptoInstance()
hash := cpt.HashStream(HASH_SHA256, stream)
b32 := cpt.EncodeStream(CODEC_BASE32, hash)
length := b32.Len()
_ = length
dest.b32 = string(b32.Bytes())
dest.b32 += ".b32.i2p"
Debug(tag, "New destination %s", dest.b32)
}
func (dest *Destination) generateB64() {
stream := NewStream(make([]byte, 0, DEST_SIZE))
dest.WriteToMessage(stream)
cpt := GetCryptoInstance()
if stream.Len() > 0 {
fmt.Printf("Stream len %d \n", stream.Len())
}
b64B := cpt.EncodeStream(CODEC_BASE64, stream)
replaced := strings.Replace(string(b64B.Bytes()), "/", "~", -1)
replaced = strings.Replace(replaced, "/", "~", -1)
dest.b64 = replaced
}