crypto_25519.go (4465B)
1 package damlib 2 3 /* 4 * Copyright (c) 2017-2018 Dyne.org Foundation 5 * tor-dam is written and maintained by Ivan Jelincic <parazyd@dyne.org> 6 * 7 * This file is part of tor-dam 8 * 9 * This program is free software: you can redistribute it and/or modify 10 * it under the terms of the GNU Affero General Public License as published by 11 * the Free Software Foundation, either version 3 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU Affero General Public License for more details. 18 * 19 * You should have received a copy of the GNU Affero General Public License 20 * along with this program. If not, see <http://www.gnu.org/licenses/>. 21 */ 22 23 import ( 24 "crypto" 25 "crypto/rand" 26 "crypto/sha512" 27 "encoding/base32" 28 "encoding/base64" 29 "io/ioutil" 30 "log" 31 "strings" 32 33 "golang.org/x/crypto/ed25519" 34 "golang.org/x/crypto/sha3" 35 ) 36 37 // GenEd25519 generates an ed25519 keypair. Returns error on failure. 38 func GenEd25519() (ed25519.PublicKey, ed25519.PrivateKey, error) { 39 log.Println("Generating ed25519 keypair...") 40 41 pk, sk, err := ed25519.GenerateKey(rand.Reader) 42 if err != nil { 43 return nil, nil, err 44 } 45 return pk, sk, nil 46 } 47 48 // SavePrivEd25519 writes a ed25519.PrivateKey type to a given string filename. 49 // Expands ed25519.PrivateKey to (a || RH) form, writing base64. Returns error 50 // upon failure. 51 func SavePrivEd25519(filename string, key ed25519.PrivateKey) error { 52 log.Println("Writing ed25519 private key to", filename) 53 54 h := sha512.Sum512(key[:32]) 55 // Set bits so that h[:32] is a private scalar "a". 56 h[0] &= 248 57 h[31] &= 127 58 h[31] |= 64 59 // Since h[32:] is RH, h is now (a || RH) 60 encoded := base64.StdEncoding.EncodeToString(h[:]) 61 return ioutil.WriteFile(filename, []byte(encoded), 0600) 62 } 63 64 // SaveSeedEd25519 saves the ed25519 private key seed to a given string filename 65 // for later reuse. Returns error upon failure. 66 func SaveSeedEd25519(filename string, key ed25519.PrivateKey) error { 67 log.Println("Writing ed25519 private key seed to", filename) 68 69 encoded := base64.StdEncoding.EncodeToString(key.Seed()) 70 return ioutil.WriteFile(filename, []byte(encoded), 0600) 71 } 72 73 // LoadEd25519KeyFromSeed loads a key from a given seed file and returns 74 // ed25519.PrivateKey. Otherwise, on failure, it returns error. 75 func LoadEd25519KeyFromSeed(filename string) (ed25519.PrivateKey, error) { 76 log.Println("Loading ed25519 private key from seed in", filename) 77 78 data, err := ioutil.ReadFile(filename) 79 if err != nil { 80 return nil, err 81 } 82 83 decoded, err := base64.StdEncoding.DecodeString(string(data)) 84 if err != nil { 85 return nil, err 86 } 87 return ed25519.NewKeyFromSeed(decoded), nil 88 } 89 90 // SignMsgEd25519 signs a message using ed25519. Returns the signature in the 91 // form of []byte, or returns an error if it fails. 92 func SignMsgEd25519(message []byte, key ed25519.PrivateKey) ([]byte, error) { 93 log.Println("Signing message...") 94 95 sig, err := key.Sign(rand.Reader, message, crypto.Hash(0)) 96 if err != nil { 97 return nil, err 98 } 99 return sig, nil 100 } 101 102 // OnionFromPubkeyEd25519 generates a valid onion address from a given ed25519 103 // public key. Returns the onion address as a slice of bytes. 104 // 105 // Tor Spec excerpt from https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt 106 // --- 107 // 6. Encoding onion addresses [ONIONADDRESS] 108 // The onion address of a hidden service includes its identity public key, a 109 // version field and a basic checksum. All this information is then base32 110 // encoded as shown below: 111 // 112 // onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion" 113 // CHECKSUM = H(".onion checksum" | PUBKEY | VERSION)[:2] 114 // 115 // where: 116 // - PUBKEY is the 32 bytes ed25519 master pubkey of the hidden service. 117 // - VERSION is an one byte version field (default value '\x03') 118 // - ".onion checksum" is a constant string 119 // - CHECKSUM is truncated to two bytes before inserting it in onion_address 120 func OnionFromPubkeyEd25519(pubkey ed25519.PublicKey) []byte { 121 const salt = ".onion checksum" 122 const version = byte(0x03) 123 124 h := []byte(salt) 125 h = append(h, pubkey...) 126 h = append(h, version) 127 128 csum := sha3.Sum256(h) 129 checksum := csum[:2] 130 131 enc := pubkey[:] 132 enc = append(enc, checksum...) 133 enc = append(enc, version) 134 135 encoded := base32.StdEncoding.EncodeToString(enc) 136 return []byte(strings.ToLower(encoded) + ".onion") 137 }