> For the complete documentation index, see [llms.txt](https://easonwang.gitbook.io/golang/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://easonwang.gitbook.io/golang/he-xin-mo-zu/crypto.md).

# crypto

## Crypto

<https://golang.org/pkg/crypto/>

### SHA256

包含了sha224 與 sha256

```go
package main

import (
    "crypto/sha256"
    "fmt"
)

func main() {
    sum := sha256.Sum256([]byte("hello world\n"))
    fmt.Printf("%x", sum)
}
```

<https://play.golang.org/p/Ky4kmHLqly>

### SHA3

(包含原生sha3和SHAKE)

> The SHAKE instances are faster than the SHA3 instances

<https://godoc.org/golang.org/x/crypto/sha3>

```go
package main

import (
    "fmt"
    "golang.org/x/crypto/sha3"
)

func main() {
    buf := []byte("some")
    h := make([]byte, 32)
    d := sha3.NewShake256()
    d.Write(buf)
    d.Read(h)
    fmt.Printf("%x\n", h)
}
```

等同於

```go
package main

import (
    "fmt"
    "golang.org/x/crypto/sha3"
)

func main() {
    buf := []byte("some")
    // A hash needs to be 64 bytes long to have 256-bit collision resistance.
    h := make([]byte, 32)
    // Compute a 64-byte hash of buf and put it in h.
    sha3.ShakeSum256(h, buf)
    fmt.Printf("%x\n", h)
}
```

### RIPEMD160

```go
package main

import (
    "golang.org/x/crypto/ripemd160"
    "fmt"
)

func main() {
    h := ripemd160.New()
    h.Write([]byte("hello"))
    fmt.Printf("%x\n", h.Sum(nil))
}
```

### HMAC

<https://golang.org/pkg/crypto/hmac/>

```go
package main

import (
        "crypto/hmac"  
        "crypto/sha256"  
    "fmt"
)

func main() {
    key := []byte("I am key")
    mac := hmac.New(sha256.New, key)
    mac.Write([]byte("msg"))
    fmt.Printf("%x\n", mac.Sum(nil))
}
```

### ECDSA

```go
package main

import (
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/md5"
    "crypto/rand"
    "fmt"
    "hash"
    "io"
    "math/big"
    "os"
)

func main() {

    Curve := elliptic.P256() //see http://golang.org/pkg/crypto/elliptic/#P256

    privatekey, err := ecdsa.GenerateKey(Curve, rand.Reader) // this generates a public & private key pair

    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    pubkey := privatekey.PublicKey
    fmt.Printf("%+v\n", privatekey.PublicKey.X)
    fmt.Println("Private Key :")
    fmt.Printf("%x \n", privatekey)

    fmt.Println("Public Key :")
    fmt.Printf("%x \n", pubkey)
    fmt.Printf("%+v\n", pubkey) // 印出struct

    // Sign ecdsa style

    var h hash.Hash
    h = md5.New()
    r := big.NewInt(0)
    s := big.NewInt(0)

    io.WriteString(h, "This is a message to be signed and verified by ECDSA!")
    signhash := h.Sum(nil)

    r, s, serr := ecdsa.Sign(rand.Reader, privatekey, signhash)
    if serr != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    // Verify
    verifystatus := ecdsa.Verify(&pubkey, signhash, r, s)
    fmt.Println(verifystatus) // should be true
}
```

## AES

```go
package main

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"strings"
)

func addBase64Padding(value string) string {
	m := len(value) % 4
	if m != 0 {
		value += strings.Repeat("=", 4-m)
	}

	return value
}

func removeBase64Padding(value string) string {
	return strings.Replace(value, "=", "", -1)
}

func Pad(src []byte) []byte {
	padding := aes.BlockSize - len(src)%aes.BlockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(src, padtext...)
}

func Unpad(src []byte) ([]byte, error) {
	length := len(src)
	unpadding := int(src[length-1])

	if unpadding > length {
		return nil, errors.New("unpad error. This could happen when incorrect encryption key is used")
	}

	return src[:(length - unpadding)], nil
}

func encrypt(key []byte, text string) (string, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	msg := Pad([]byte(text))
	ciphertext := make([]byte, aes.BlockSize+len(msg))
	iv := ciphertext[:aes.BlockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return "", err
	}

	cfb := cipher.NewCFBEncrypter(block, iv)
	cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(msg))
	finalMsg := removeBase64Padding(base64.URLEncoding.EncodeToString(ciphertext))
	return finalMsg, nil
}

func decrypt(key []byte, text string) (string, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	decodedMsg, err := base64.URLEncoding.DecodeString(addBase64Padding(text))
	if err != nil {
		return "", err
	}

	if (len(decodedMsg) % aes.BlockSize) != 0 {
		return "", errors.New("blocksize must be multipe of decoded message length")
	}

	iv := decodedMsg[:aes.BlockSize]
	msg := decodedMsg[aes.BlockSize:]

	cfb := cipher.NewCFBDecrypter(block, iv)
	cfb.XORKeyStream(msg, msg)

	unpadMsg, err := Unpad(msg)
	if err != nil {
		return "", err
	}

	return string(unpadMsg), nil
}

func main() {
	key := []byte("LKHlhb899Y09olUi")
	encryptMsg, _ := encrypt(key, "test")
	msg, _ := decrypt(key, encryptMsg)
	fmt.Println(msg) // Hello World
}
```

## RSA

> 包含 OAEP 與 PKCS

先產生公鑰與私鑰

```
openssl genrsa -out private.pem 1024
openssl rsa -in private.pem -pubout -out public.pem
```

```go
package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"fmt"
)

func rsaEncrypt(origData []byte) ([]byte, error) {
	block, _ := pem.Decode(publicKey)
	if block == nil {
		return nil, errors.New("public key error")
	}
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	pub := pubInterface.(*rsa.PublicKey)
	return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
}

func rsaDecrypt(ciphertext []byte) ([]byte, error) {
	block, _ := pem.Decode(privateKey)
	if block == nil {
		return nil, errors.New("private key error")
	}
	priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
}

var privateKey = []byte(`
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDZyTI4o7pukaJN6sVklkX4sR5IRpLXzPv4/28YVD1xaPn1Q69o
7G6GfHacMtsPZDkEFeGmZBWb4YHLqRczKM3ZPSEA2/FBGZoxKiCq80NMhPngiEWy
gG+J7CyXXO9syHFpSO5AciB0P3r2aewWhVMub9bDa9uwUnMqFCmy65GB/QIDAQAB
AoGARaYZgJGkCr5aeK6vSBbi88C5HYYsagVtQ9l0zwQJzl4zKiPmUhji0/G0AQom
koqLzWmuC4eQfZSl7Nr7x2myQsMxd6W1eZhU/Jki3v/tqG5rDpDz0X0/05uOsZoe
i+6EPhRiT1Y95R2evKpcCwOtUjOD3uQZx6vmytUeEQ7U4sECQQD0rCOdE6OC1LQJ
X2xPqvM9WHeHavhktvCZWkmzfzb/wDtAcbrspS+riBCdiwesP9d7rujmhNUG6vAd
NYVqD4NxAkEA495l33ImdwsyX/IvkastyJ65JDKtS20nHWqzFGW3pVd7liGTvo5k
Iil3vwIM6Mdw/AVUubsEUIvrHC8u2cgJTQJASD9sZL2f0sosP3hF62B3Yu30nbAg
mNzMPvxCNxahjvOci3MJ10cPxH7xKRQct+hCIOuNKkSfAuPs8zMSqjbagQJAUdgI
eRgz7qAL6OBA664zFJLF5tV43tWGrg8r4RCjxHRGhGbs/Q2Bs693PhjLcDRqRWrY
wpkEdLW8rXPY/QnXJQJBAL3uYok6AeKf/UDs1/tR8RqSSWwAQC6FGXbygsLKfywD
v+6/UK1M6tc3S8jHvCZUw5Ybds0KUKMiaATX7RYUDQo=
-----END RSA PRIVATE KEY-----
`)
var publicKey = []byte(`
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZyTI4o7pukaJN6sVklkX4sR5I
RpLXzPv4/28YVD1xaPn1Q69o7G6GfHacMtsPZDkEFeGmZBWb4YHLqRczKM3ZPSEA
2/FBGZoxKiCq80NMhPngiEWygG+J7CyXXO9syHFpSO5AciB0P3r2aewWhVMub9bD
a9uwUnMqFCmy65GB/QIDAQAB
-----END PUBLIC KEY-----
`)

func main() {
	data, err := rsaEncrypt([]byte("test"))
	if err != nil {
		panic(err)
	}
	decryptedData, err := rsaDecrypt(data)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(decryptedData))
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://easonwang.gitbook.io/golang/he-xin-mo-zu/crypto.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
