tor-dam

tor distributed announce mechanism (not a dht)
git clone https://git.parazyd.org/tor-dam
Log | Files | Refs | README | LICENSE

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 }