document.write("
/* Code works but is NOT FORMALLY UNIT TESTED and should be treated as
proof of concept only - i.e. don't use for amounts exceeding $10.00 until
you have conducted your own testing. */
package main
import (
"bufio"
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcutil/base58"
"golang.org/x/crypto/ripemd160"
"golang.org/x/crypto/scrypt"
)
var (
userData, _ = ioutil.ReadFile("seed")
)
func main() {
FileOps()
}
func InputPass() (passwordB []byte) {
fmt.Print("Enter password: ")
reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\\n')
if err != nil {
fmt.Println("An error occured while reading input. Please try again", err)
}
password := strings.TrimSuffix(input, "\\n")
passwordB = []byte(password)
return passwordB
}
func InputMode() (modeB []byte) {
fmt.Print("Enter mode choice [e/c]: press e key to create an encrypted AES file, press c key to decrypt an existing AES and use it to create a private key:")
reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\\n')
if err != nil {
fmt.Println("An error occured while reading input. Please try again", err)
return
}
mode := strings.TrimSuffix(input, "\\n")
modeB = []byte(mode)
return modeB
}
func EncryptSeed(key, file []byte) ([]byte, error) {
key, salt, err := DeriveKey(key, nil)
if err != nil {
return nil, err
}
blockCipher, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(blockCipher)
if err != nil {
return nil, err
}
nonce := make([]byte, gcm.NonceSize())
if _, err = rand.Read(nonce); err != nil {
return nil, err
}
ciphertext := gcm.Seal(nonce, nonce, file, nil)
ciphertext = append(ciphertext, salt...)
return ciphertext, nil
}
func DecryptSeed(key, file []byte) ([]byte, error) {
salt, file := file[len(file)-32:], file[:len(file)-32]
key, _, err := DeriveKey(key, salt)
if err != nil {
return nil, err
}
blockCipher, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(blockCipher)
if err != nil {
return nil, err
}
nonce, ciphertext := file[:gcm.NonceSize()], file[gcm.NonceSize():]
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, err
}
return plaintext, nil
}
func DeriveKey(password, salt []byte) ([]byte, []byte, error) {
if salt == nil {
salt = make([]byte, 32)
if _, err := rand.Read(salt); err != nil {
return nil, nil, err
}
}
key, err := scrypt.Key(password, salt, 1048576, 8, 1, 32)
if err != nil {
return nil, nil, err
}
return key, salt, nil
}
func FileOps() []byte {
var ret []byte
mode := string(InputMode())
strMode := string(mode)
if strMode == "e" {
password := InputPass()
ciphertext, err := EncryptSeed(password, userData)
if err != nil {
log.Fatal(err)
}
f, err := os.Create("a_aes.txt")
if err != nil {
panic(err.Error())
}
_, err = io.Copy(f, bytes.NewReader(ciphertext))
if err != nil {
panic(err.Error())
}
os.Remove("seed")
return ret
}
if strMode == "c" {
password := InputPass()
ciphertext2, err := ioutil.ReadFile("a_aes.txt")
if err != nil {
panic(err.Error())
}
plaintext, err := DecryptSeed(password, ciphertext2)
if err != nil {
log.Fatal(err)
}
WalletOps(plaintext)
return plaintext
}
if strMode != "c" && strMode != "e" {
fmt.Println("Please try again and enter e or c.")
return ret
}
return ret
}
func WalletOps(fromAES []byte) {
qrng := GetQrng()
aesFileInfo := string(fromAES)
bAesFileInfo := []byte(aesFileInfo + qrng)
hash := sha256.Sum256(bAesFileInfo)
stretchedKey := StretchKey(255, hash, qrng)
_, pub := btcec.PrivKeyFromBytes(btcec.S256(), stretchedKey[:])
fmt.Println("")
fmt.Println("====")
fmt.Println("Wallet Address:", WalletAddressB58(pub.SerializeUncompressed()))
fmt.Println("====")
fmt.Println("")
fmt.Println("====")
fmt.Println("Wallet WIF:", WalletWifB58(stretchedKey[:]))
fmt.Println("====")
fmt.Println("")
}
func GetQrng() (string) {
resp, err := http.Get("https://qrng.anu.edu.au/API/jsonI.php?length=32&type=uint8")
if err != nil {
log.Fatalln(err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
if resp.StatusCode != 200 {
log.Fatalln("None 200 status code returned, please try again")
}
type Data []uint8
type JsonData struct {
Data Data
}
var data JsonData
e := json.Unmarshal(body, &data)
if e != nil {
fmt.Println("JSON error occurred")
}
strEnc := base64.StdEncoding.EncodeToString(data.Data[:])
sha := sha256.Sum256([]byte(strEnc))
base64str := base64.StdEncoding.EncodeToString(sha[:])
return base64str
}
func StretchKey(iter int, hash [32]byte, qrng string) ([32]byte) {
j := 0
for j < iter {
base64str := base64.StdEncoding.EncodeToString(hash[:])
new := base64str + qrng
newHash := sha256.Sum256([]byte(new))
hash = newHash
j++
}
return hash
}
func ShaRipe(b []byte) []byte {
s := sha256.Sum256(b)
r := ripemd160.New()
r.Write(s[:])
return r.Sum([]byte{})
}
func ShaSha(b []byte) []byte {
x := sha256.Sum256(b)
y := sha256.Sum256(x[:])
return y[:]
}
func WalletAddress(pubkey []byte) []byte {
if len(pubkey) == 64 {
pubkey = append([]byte{4}, pubkey...)
}
hash := ShaRipe(pubkey)
hash = append([]byte{0}, hash...)
checksum := ShaSha(hash)
return append(hash, checksum[0:4]...)
}
func WalletAddressB58(pubkey []byte) string {
return base58.Encode(WalletAddress(pubkey))
}
func WalletWif(privkey []byte) []byte {
bytes := append([]byte{0x80}, privkey...)
checksum := ShaSha(bytes)
return append(bytes, checksum[0:4]...)
}
func WalletWifB58(privkey []byte) string {
return base58.Encode(WalletWif(privkey))
}
main.go - Snippet hosted by \"Cacher\"
");