39

我正在尝试加密数据库中的一些文本,以便在程序启动期间加载和解密。

我尝试了一些方法,包括第三方库https://github.com/richard-lyman/lithcrypt无济于事。使用以下方法加密/解密 8/10 项,但似乎在加密/解密中的某个点留下了一些填充残留物。就目前而言,我的代码是这样的:

package client                                                                                                                                                                                              
import (                                                                                                                                                                                                    
    "encoding/base64"                                                                                                                                                                                       
    "crypto/aes"                                                                                                                                                                                            
    "crypto/cipher"                                                                                                                                                                                         
    "fmt"                                                                                                                                                                                                   
) 

var iv = []byte{34, 35, 35, 57, 68, 4, 35, 36, 7, 8, 35, 23, 35, 86, 35, 23}

func encodeBase64(b []byte) string {                                                                                                                                                                        
    return base64.StdEncoding.EncodeToString(b)                                                                                                                                                             
}                                                                                                                                                                                                           

func decodeBase64(s string) []byte {                                                                                                                                                                        
    data, err := base64.StdEncoding.DecodeString(s)                                                                                                                                                         
    if err != nil { panic(err) }                                                                                                                                                                            
    return data                                                                                                                                                                                             
}                                                                                                                                                                                                           

func Encrypt(key, text string) string {                                                                                                                                                                     
    block, err := aes.NewCipher([]byte(key))                                                                                                                                                                
    if err != nil { panic(err) }                                                                                                                                                                            
    plaintext := []byte(text)                                                                                                                                                                               
    cfb := cipher.NewCFBEncrypter(block, iv)                                                                                                                                                                
    ciphertext := make([]byte, len(plaintext))                                                                                                                                                              
    cfb.XORKeyStream(ciphertext, plaintext)                                                                                                                                                                 
    return encodeBase64(ciphertext)                                                                                                                                                                         
}                                                                                                                                                                                                           

func Decrypt(key, text string) string {                                                                                                                                                                     
    block, err := aes.NewCipher([]byte(key))                                                                                                                                                                
    if err != nil { panic(err) }                                                                                                                                                                            
    ciphertext := decodeBase64(text)                                                                                                                                                                        
    cfb := cipher.NewCFBEncrypter(block, iv)                                                                                                                                                                
    plaintext := make([]byte, len(ciphertext))                                                                                                                                                              
    cfb.XORKeyStream(plaintext, ciphertext)                                                                                                                                                                 
}                          

有人提到我可能需要填充字符串,但我必须填充流密码似乎很奇怪。

下面是这个错误的一个例子:http ://play.golang.org/p/4FQBAeHgRs

4

6 回答 6

63

这是基于NewCFBEncrypter / NewCFBDecrypter 示例,似乎可以满足您的要求:

编辑:根据 Kluyg 关于 IV 创建的评论,我修改了示例代码以使用推荐的从密文创建 IV 的方法与链接示例相同的方法从密文创建 IV。(在生产代码中,IV 应该每次单独生成。感谢RoundSparrow hilltx指出这一点。)

我认为您遇到的问题是由于密钥长度无效,但我不是 100% 确定。

package main

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

func main() {
    key := []byte("a very very very very secret key") // 32 bytes
    plaintext := []byte("some really really really long plaintext")
    fmt.Printf("%s\n", plaintext)
    ciphertext, err := encrypt(key, plaintext)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%0x\n", ciphertext)
    result, err := decrypt(key, ciphertext)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s\n", result)
}

// See alternate IV creation from ciphertext below
//var iv = []byte{35, 46, 57, 24, 85, 35, 24, 74, 87, 35, 88, 98, 66, 32, 14, 05}

func encrypt(key, text []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    b := base64.StdEncoding.EncodeToString(text)
    ciphertext := make([]byte, aes.BlockSize+len(b))
    iv := ciphertext[:aes.BlockSize]
    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
        return nil, err
    }
    cfb := cipher.NewCFBEncrypter(block, iv)
    cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
    return ciphertext, nil
}

func decrypt(key, text []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    if len(text) < aes.BlockSize {
        return nil, errors.New("ciphertext too short")
    }
    iv := text[:aes.BlockSize]
    text = text[aes.BlockSize:]
    cfb := cipher.NewCFBDecrypter(block, iv)
    cfb.XORKeyStream(text, text)
    data, err := base64.StdEncoding.DecodeString(string(text))
    if err != nil {
        return nil, err
    }
    return data, nil
}

产生:

一些非常非常长的纯文本
54618bd6bb10612a7b590c53192df214501e01b685540b012581a0ed9ff3ddaa1f4177cc6186b501fb8cce0c2eb764daff475aab724d4d33e614d7d892001
非常长的纯文本

操场

希望这有助于查明问题。

于 2013-09-16T00:52:21.960 回答
10

加密很难,go 库可能不够高级,所以很容易出错。

对于任何寻求该领域专家(CoreOS 的安全开发人员)正确执行此操作的示例的人来说,这提供了一个很好的 AES 加密示例(以及加密的其他常见用途)。

https://github.com/gtank/cryptopasta

于 2017-03-14T12:36:58.617 回答
4

看来您的操作顺序有点倒退。这是您似乎正在做的事情:

ct = encrypt(encode(pt))
pt = decode(decrypt(ct))

它应该看起来更像:

ct = encode(encrypt(pt))
pt = decrypt(decode(ct))

以下对我有用

func Encrypt(key, text []byte) string {
    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }
    ciphertext := make([]byte, aes.BlockSize+len(text))
    iv := ciphertext[:aes.BlockSize]
    if _, err := io.ReadFull(crand.Reader, iv); err != nil {
        panic(err)
    }
    cfb := cipher.NewCFBEncrypter(block, iv)
    cfb.XORKeyStream(ciphertext[aes.BlockSize:], text)
    return encodeBase64(ciphertext)
}


func Decrypt(key []byte, b64 string) string {
    text := decodeBase64(b64)
    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }
    if len(text) < aes.BlockSize {
        panic("ciphertext too short")
    }
    iv := text[:aes.BlockSize]
    text = text[aes.BlockSize:]
    cfb := cipher.NewCFBDecrypter(block, iv)
    cfb.XORKeyStream(text, text)
    return string(text)
}
于 2014-07-03T05:17:27.527 回答
4

这是我刚刚完成的工作演示,它主要使用 go 文档中的代码示例,但它是为执行大多数应用程序(包括我的用例)期望的加密方法而量身定制的。

它使用AES加密。从字符串加密到base64字符串。易于在 URL 和 dbs 上使用。从上面创建的 base64 字符串解密为原始文本。

随处可见的简单文本转换。

GIST:这是要点,如果需要改进,请告诉我。

这是一个简单的 go 文件,可以运行了。

于 2014-01-02T17:22:19.347 回答
1

许多人已经提供了很好的答案。但是正如@PiersyP 在@Intermernet 答案的评论中指出的那样,没有必要对文本进行base64。所以这里没有base64ing,以防有人赶时间

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "errors"
    "fmt"
    "io"
    "log"
)

func main() {
    key := []byte("a very very very very secret key") // 32 bytes
    plaintext := []byte("some really really really long plaintext")
    fmt.Printf("%s\n", plaintext)
    ciphertext, err := encrypt(key, plaintext)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%0x\n", ciphertext)
    result, err := decrypt(key, ciphertext)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s\n", result)
}

// See alternate IV creation from ciphertext below
//var iv = []byte{35, 46, 57, 24, 85, 35, 24, 74, 87, 35, 88, 98, 66, 32, 14, 05}

func encrypt(key, text []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    ciphertext := make([]byte, aes.BlockSize + len(text))
    iv := ciphertext[:aes.BlockSize]
    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
        return nil, err
    }
    cfb := cipher.NewCFBEncrypter(block, iv)
    cfb.XORKeyStream(ciphertext[aes.BlockSize:], text)
    return ciphertext, nil
}

func decrypt(key, text []byte) ([]byte, error) {
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }
    if len(text) < aes.BlockSize {
        return nil, errors.New("ciphertext too short")
    }
    iv := text[:aes.BlockSize]
    text = text[aes.BlockSize:]
    cfb := cipher.NewCFBDecrypter(block, iv)
    cfb.XORKeyStream(text, text)
    return text, nil
}
于 2020-04-21T20:18:40.163 回答
1

实际上没有回答这个问题。但是我在这里为来自搜索引擎的人提供了一个完整的工作示例。

通过添加hash password. _ 您可以使用任何密码而不必担心其大小。

去游乐场

package main

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

func main() {
    key := []byte("secret")
    ct, err := Encrypt([]byte("Plain text"), key)
    if err != nil {
        panic(err)
    }

    fmt.Println("Encrypted:", base64.StdEncoding.EncodeToString(ct))

    pt, err := Decrypt(ct, key)
    if err != nil {
        panic(err)
    }
    fmt.Println("Decrypted:", string(pt))
}

// Encrypt encrypts data using 256-bit AES-GCM.  This both hides the content of
// the data and provides a check that it hasn't been altered. Output takes the
// form nonce|ciphertext|tag where '|' indicates concatenation.
func Encrypt(plaintext []byte, key []byte) (ciphertext []byte, err error) {
    k := sha256.Sum256(key)
    block, err := aes.NewCipher(k[:])
    if err != nil {
        return nil, err
    }

    gcm, err := cipher.NewGCM(block)
    if err != nil {
        return nil, err
    }

    nonce := make([]byte, gcm.NonceSize())
    _, err = io.ReadFull(rand.Reader, nonce)
    if err != nil {
        return nil, err
    }

    return gcm.Seal(nonce, nonce, plaintext, nil), nil
}

// Decrypt decrypts data using 256-bit AES-GCM.  This both hides the content of
// the data and provides a check that it hasn't been altered. Expects input
// form nonce|ciphertext|tag where '|' indicates concatenation.
func Decrypt(ciphertext []byte, key []byte) (plaintext []byte, err error) {
    k := sha256.Sum256(key)
    block, err := aes.NewCipher(k[:])
    if err != nil {
        return nil, err
    }

    gcm, err := cipher.NewGCM(block)
    if err != nil {
        return nil, err
    }

    if len(ciphertext) < gcm.NonceSize() {
        return nil, errors.New("malformed ciphertext")
    }

    return gcm.Open(nil,
        ciphertext[:gcm.NonceSize()],
        ciphertext[gcm.NonceSize():],
        nil,
    )
}

于 2021-07-07T09:35:51.123 回答