Golang implementation ANProto: the Authenticated and Non-networked protocol or ANother protocol
1package goan
2
3import (
4 "crypto/ed25519"
5 "crypto/sha256"
6 "encoding/base64"
7 "errors"
8 "strconv"
9 "time"
10)
11
12// Gen returns base64(publicKey)+base64(secretKey)
13func Gen() (string, error) {
14 pub, priv, err := ed25519.GenerateKey(nil)
15 if err != nil {
16 return "", err
17 }
18 pubB := base64.StdEncoding.EncodeToString(pub)
19 privB := base64.StdEncoding.EncodeToString(priv)
20 return pubB + privB, nil
21}
22
23func Hash(d string) string {
24 h := sha256.Sum256([]byte(d))
25 return base64.StdEncoding.EncodeToString(h[:])
26}
27
28func Sign(h string, k string) (string, error) {
29 if len(k) < 44+88 {
30 return "", errors.New("invalid key length")
31 }
32 pubB := k[:44]
33 privB := k[44:]
34 priv, err := base64.StdEncoding.DecodeString(privB)
35 if err != nil {
36 return "", err
37 }
38 msg := []byte(strconv.FormatInt(time.Now().UnixNano()/1e6, 10) + h)
39 sig := ed25519.Sign(priv, msg)
40 signed := append(sig, msg...)
41 signedB := base64.StdEncoding.EncodeToString(signed)
42 return pubB + signedB, nil
43}
44
45func Open(m string) (string, error) {
46 if len(m) < 44 {
47 return "", errors.New("invalid message")
48 }
49 pubB := m[:44]
50 signedB := m[44:]
51 signed, err := base64.StdEncoding.DecodeString(signedB)
52 if err != nil {
53 return "", err
54 }
55 if len(signed) < ed25519.SignatureSize {
56 return "", errors.New("signed message too short")
57 }
58 sig := signed[:ed25519.SignatureSize]
59 msg := signed[ed25519.SignatureSize:]
60 pub, err := base64.StdEncoding.DecodeString(pubB)
61 if err != nil {
62 return "", err
63 }
64 if !ed25519.Verify(pub, msg, sig) {
65 return "", errors.New("signature verification failed")
66 }
67 return string(msg), nil
68}