OpenResty AES 函数密钥生成原理

最近遇到一个场景,需要在 OpenResty 里使用 AES 对数据进行加密。但是看了一下官方提供的 AES 库,如果数据密码的话,并没有返回实际使用的 key 和 IV,因此查看了一下源码,研究了一下 key 生成的方式,方便其他语言使用。

密钥生成逻辑的核心代码在这:

function _M.new(self, key, salt, _cipher, _hash, hash_rounds, iv_len, enable_padding)

...

    local _hash = _hash or hash.md5
    local hash_rounds = hash_rounds or 1

...

        if C.EVP_BytesToKey(_cipher.method, _hash, salt, key, #key,
                            hash_rounds, gen_key, gen_iv)
            ~= _cipherLength
        then
            return nil, "failed to generate key and iv"
        end
end

其中最核心的部分就是使用了 EVP_BytesToKey 这个函数,进行密钥扩展。这个函数是 OpenSSL 库提供的函数,相关说明在这:

https://www.openssl.org/docs/man3.1/man3/EVP_BytesToKey.html

注意!该函数并不安全!一般不建议在生产中使用该函数!应当使用安全的密钥衍生函数(KDF)!

阅读文档,该函数的主要做法就是对提供的密码进行 hash,如果长度不够 key 或 iv 的要求,则继续进行 hash,直到长足足够为止。

第一轮 hash 直接拼接给定的密码和 salt,从第二轮开始,则将上一轮的结果附加在密码和 salt 前,然后再次进行 hash 操作。注意这里从第二轮开始附加的上一轮结果是二进制结果,如果希望手动使用工具计算的话,需要将 hex 编码或 base64 编码后的结果先进行解码,再附加在输入前。

用 Go 模拟这个过程的代码如下:

package main

import (
    "crypto/sha256"
    "fmt"
)

// EVPBytesToKey 模拟 OpenSSL EVP_BytesToKey 方法
func EVPBytesToKey(password, salt []byte, keyLen, ivLen int) (key, iv []byte) {
    var (
        concatenatedHashes []byte
        previousHash       []byte
        currentHash        []byte
        hash               = sha256.New()
    )

    for len(concatenatedHashes) < keyLen+ivLen {
        hash.Reset()

        // 如果不是第一轮,将上一轮的哈希值加到当前哈希的输入中
        if previousHash != nil {
            hash.Write(previousHash)
        }

        // 加入密码和盐值
        hash.Write(password)
        hash.Write(salt)

        // 当前哈希
        currentHash = hash.Sum(nil)

        // 添加到累积哈希中
        concatenatedHashes = append(concatenatedHashes, currentHash...)

        // 为下一轮准备
        previousHash = currentHash
    }

    // 提取密钥和 IV
    key = concatenatedHashes[:keyLen]
    iv = concatenatedHashes[keyLen : keyLen+ivLen]
    return key, iv
}

func main() {
    password := []byte("password")
    salt := []byte("salt")
    keyLen := 32 // AES-256 需要的密钥长度
    ivLen := 16  // AES 的 IV 长度

    key, iv := EVPBytesToKey(password, salt, keyLen, ivLen)
    fmt.Printf("Key: %x\nIV: %x\n", key, iv)
}

10大最适合编程的字体推荐下载,让代码看起来更美更舒服!

现在有事没事就喜欢写写代码的人越来越多了,对于成天盯着屏幕工作的开发人员来说,编程代码可能是每天见得最多的东西了。可是绝大部分人都一直使用编辑器默认的字体,其实,换一套适合自己的编程字体不仅能让代码看得更舒服,甚至还能提高工作效率的!

如果你有想过换一种编程字体,却不知道哪里找合适的,那么看看异次元软件世界为您推荐的10款最适合编程的字体吧,这些字体能让你的代码瞬间“优雅”起来!换一种字体,换一番心情嘛。当然,除了编程之外,经常需要编辑英文文档的朋友同样适用……

前言:

下面字体的排序是作者的主观感受,每个人的喜好都不一样。建议您都试试,按照自己的喜好来选择。另外,还在使用 Windows XP 的同学,如果您希望显示到如截图中清晰的字体效果,则必须安装微软的ClearType设置程序对清晰度进行设置。

10. Courier

也叫Courier New,这大概是我们最熟悉的字体了,基本上所有系统都有。很不幸,很多终端和编辑器都默认使用此种字体,虽然不会影响使用,但它太无趣了。如果你正在使用这种字体,建议调大一点,并打开系统的 anti-aliasing (抗锯齿) 设置。

clip_image001

下载 Courier New 字体

9. Andale Mono

比Courier稍好,也是常见的默认字体。我感觉字母太宽了,字符间距也比较蠢。

clip_image002

下载 Andale Mono 字体

8. Monaco

Mac的默认字体,好像也只有Mac上有。小字号的时候表现不错,而且再大些也不寒碜。

clip_image003

下载 Monaco 字体

7. Profont

与Monaco类似的位图字体,你能够在Mac, Windows和Linux上面使用。小字号的时候表现好。非Mac平台上Monaco的最佳替代。喜欢小字号且不怕眼睛疲劳的同学可以考虑。

clip_image004

下载 Profont 字体

6. Monofur

独特的等宽字体,各种字号下都表现不错,但是需要设置anti-aliasing。怀旧而且喜欢与众不同的人推荐。

clip_image005

下载 Monofur 字体

5. Proggy

干净的等宽字体,好像很受Windows用户欢迎,但在Mac上也不错。使用时,字号可以小一点,无需anti-aliasing。

clip_image006

下载 Proggy 字体

4. Droid Sans Mono

开源字体,可以在这里下载,适合手机屏幕。是等宽字体中最突出的一个。可惜0和O区别不大。

clip_image007

下载 Droid Sans Mono 字体

3. Deja Vu Sans Mono

我最喜欢的免费字体系列,以Vera为基础,但是比后者提供更多字符了。适于任何字号,需要anti-aliasing。

clip_image008

下载 Deja Vu Sans Mono 字体

2. Consolas + 中文雅黑混合版

Consolas 是商业字体,专门为微软设计,微软不少产品上都有,所以很可能你的系统上已经有了。需要anti-aliasing。如果不是商业的,我可能就把它放第一了。Consolas仅含英文字母部分,这里提供的是雅黑中文+Consolas英文的混合体,即使代码里有中文注释显示效果也能很好的!

clip_image009

下载 Consolas 雅黑字体

1. Inconsolata

我最喜欢的等宽字体,免费。我遇到它之后,很快就把原来的默认字体Deja Vu Sans Mono抛弃了。真正适合任何字号的好字体。感谢它的创造者Raph Levien!

clip_image010

下载 Inconsolata 字体