我使用的是PKCS#7Padding,它的思想很简单但也很巧妙:缺 n 个 byte,便填补 n 个值为 n 的 byte。而为了能够确认明文是否添加过 Padding,选择的做法是 always-padded,即便明文的长度恰好能够被模块长度整除,我们也会去添加一个虚块(dummy block),实现如下:
// according to https://www.rfc-editor.org/rfc/rfc2315: // // 2. Some content-encryption algorithms assume the // input length is a multiple of k octets, where k > 1, and // let the application define a method for handling inputs // whose lengths are not a multiple of k octets. For such // algorithms, the method shall be to pad the input at the // trailing end with k - (l mod k) octets all having value k - // (l mod k), where l is the length of the input. In other // words, the input is padded at the trailing end with one of // the following strings: // // 01 -- if l mod k = k-1 // 02 02 -- if l mod k = k-2 // . // . // . // k k ... k k -- if l mod k = 0 // // The padding can be removed unambiguously since all input is // padded and no padding string is a suffix of another. This // padding method is well-defined if and only if k < 256; // methods for larger k are an open issue for further study. //
// calculate the padding length, ranging from 1 to blockSize paddingLen := blockSize - len(data)%blockSize
// build the padding text padding := bytes.Repeat([]byte{byte(paddingLen)}, paddingLen) returnappend(data, padding...), nil }
// The IV needs to be unique, but not secure. Therefore it's common to // include it at the beginning of the ciphertext. cipherText := make([]byte, blockSize+sha256.Size+len(plainText)) iv := cipherText[:blockSize] mac := cipherText[blockSize : blockSize+sha256.Size] payload := cipherText[blockSize+sha256.Size:] // 3. 初始化 IV if _, err = rand.Read(iv); err != nil { returnnil, err }