【botan源码阅读】MD结构源码阅读
❝
山有木兮木有枝,心悦君兮君不知。——《越人歌》
❞
这里建议,如果说没有看过那篇MD5解析的读者先看一下上一篇文章,这里重复的内容就不再次解读了。这一篇文章呢,我们会来直接解读在源码当中试用过Merkle-Damgård 结构的一系列哈希函数,因为他们本身的结构都是相似的,所以干脆就在一块讲了,主要涉及到的源码目录如下:
src/lib/hash/md4
src/lib/hash/rmd160
src/lib/hash/sha1
src/lib/hash/sha2_32
src/lib/hash/sha2_64
src/lib/hash/sm3
src/lib/hash/whirlpool
MD4
我们来看,这里和md5不一样的地方,核心的分析点还是在于压缩函数上。
/*
* MD4 Compression Function
*/
void MD4::compress_n(const uint8_t input[], size_t blocks)
{
uint32_t A = m_digest[0], B = m_digest[1], C = m_digest[2], D = m_digest[3];
for(size_t i = 0; i != blocks; ++i)
{
// 加载数据
uint32_t M00 = load_le<uint32_t>(input, 0);
uint32_t M01 = load_le<uint32_t>(input, 1);
uint32_t M02 = load_le<uint32_t>(input, 2);
uint32_t M03 = load_le<uint32_t>(input, 3);
uint32_t M04 = load_le<uint32_t>(input, 4);
uint32_t M05 = load_le<uint32_t>(input, 5);
uint32_t M06 = load_le<uint32_t>(input, 6);
uint32_t M07 = load_le<uint32_t>(input, 7);
uint32_t M08 = load_le<uint32_t>(input, 8);
uint32_t M09 = load_le<uint32_t>(input, 9);
uint32_t M10 = load_le<uint32_t>(input, 10);
uint32_t M11 = load_le<uint32_t>(input, 11);
uint32_t M12 = load_le<uint32_t>(input, 12);
uint32_t M13 = load_le<uint32_t>(input, 13);
uint32_t M14 = load_le<uint32_t>(input, 14);
uint32_t M15 = load_le<uint32_t>(input, 15);
// 执行对应的压缩函数
FF4(A, B, C, D, M00, M01, M02, M03);
FF4(A, B, C, D, M04, M05, M06, M07);
FF4(A, B, C, D, M08, M09, M10, M11);
FF4(A, B, C, D, M12, M13, M14, M15);
GG4(A, B, C, D, M00, M04, M08, M12);
GG4(A, B, C, D, M01, M05, M09, M13);
GG4(A, B, C, D, M02, M06, M10, M14);
GG4(A, B, C, D, M03, M07, M11, M15);
HH4(A, B, C, D, M00, M08, M04, M12);
HH4(A, B, C, D, M02, M10, M06, M14);
HH4(A, B, C, D, M01, M09, M05, M13);
HH4(A, B, C, D, M03, M11, M07, M15);
A = (m_digest[0] += A);
B = (m_digest[1] += B);
C = (m_digest[2] += C);
D = (m_digest[3] += D);
input += hash_block_size();
}
}
这个写法呢,看起来和上一篇有一点点的不同,似乎沿用md5的写法也没有什么问题,这里为什么要在加载的时候去分成了16个参数,这波操作诡异了,一波差点给我带走,如果按照原来md5的写法,我们很容易写出来下面的代码。
// md4.h
class MD4 final : public MDx_HashFunction {
public:
size_t output_length() const override { return 16; }
void clear() override;
MD4() : MDx_HashFunction(64, false, true), m_M(16), m_digest(4) { clear(); }
private:
void compress_n(const uint8_t input[], size_t blocks) override;
void copy_out(uint8_t[]) override;
/**
* The message buffer
*/
std::vector<uint32_t> m_M;
/**
* The digest value
*/
std::vector<uint32_t> m_digest;
};
// md4.cpp
namespace {
/*
* MD4 FF Function
*/
template<size_t S>
inline void FF4(uint32_t &A, uint32_t B, uint32_t C, uint32_t D, uint32_t M) {
A += choose(B, C, D) + M;
A = rotl<S>(A);
}
/*
* MD4 GG Function
*/
template<size_t S>
inline void GG4(uint32_t &A, uint32_t B, uint32_t C, uint32_t D, uint32_t M) {
A += ((B & C) | (D & (B | C))) + M + 0x5A827999;
A = rotl<S>(A);
}
/*
* MD4 HH Function
*/
template<size_t S>
inline void HH4(uint32_t &A, uint32_t B, uint32_t C, uint32_t D, uint32_t M) {
A += (B ^ C ^ D) + M + 0x6ED9EBA1;
A = rotl<S>(A);
}
}
#pragma clang diagnostic push
#pragma ide diagnostic ignored "ArgumentSelectionDefects"
/*
* MD4 Compression Function
*/
void MD4::compress_n(const uint8_t input[], size_t blocks) {
uint32_t A = m_digest[0], B = m_digest[1], C = m_digest[2], D = m_digest[3];
for (size_t i = 0; i != blocks; ++i) {
load_le(m_M.data(), input, m_M.size());
FF4<3>(A, B, C, D, m_M[0]);
FF4<7>(D, A, B, C, m_M[1]);
FF4<11>(C, D, A, B, m_M[2]);
FF4<19>(B, C, D, A, m_M[3]);
FF4<3>(A, B, C, D, m_M[4]);
FF4<7>(D, A, B, C, m_M[5]);
FF4<11>(C, D, A, B, m_M[6]);
FF4<19>(B, C, D, A, m_M[7]);
FF4<3>(A, B, C, D, m_M[8]);
FF4<7>(D, A, B, C, m_M[9]);
FF4<11>(C, D, A, B, m_M[10]);
FF4<19>(B, C, D, A, m_M[11]);
FF4<3>(A, B, C, D, m_M[12]);
FF4<7>(D, A, B, C, m_M[13]);
FF4<11>(C, D, A, B, m_M[14]);
FF4<19>(B, C, D, A, m_M[15]);
GG4<3>(A, B, C, D, m_M[0]);
GG4<5>(D, A, B, C, m_M[4]);
GG4<9>(C, D, A, B, m_M[8]);
GG4<13>(B, C, D, A, m_M[12]);
GG4<3>(A, B, C, D, m_M[1]);
GG4<5>(D, A, B, C, m_M[5]);
GG4<9>(C, D, A, B, m_M[9]);
GG4<13>(B, C, D, A, m_M[13]);
GG4<3>(A, B, C, D, m_M[2]);
GG4<5>(D, A, B, C, m_M[6]);
GG4<9>(C, D, A, B, m_M[10]);
GG4<13>(B, C, D, A, m_M[14]);
GG4<3>(A, B, C, D, m_M[3]);
GG4<5>(D, A, B, C, m_M[7]);
GG4<9>(C, D, A, B, m_M[11]);
GG4<13>(B, C, D, A, m_M[15]);
HH4<3>(A, B, C, D, m_M[0]);
HH4<9>(D, A, B, C, m_M[8]);
HH4<11>(C, D, A, B, m_M[4]);
HH4<15>(B, C, D, A, m_M[12]);
HH4<3>(A, B, C, D, m_M[2]);
HH4<9>(D, A, B, C, m_M[10]);
HH4<11>(C, D, A, B, m_M[6]);
HH4<15>(B, C, D, A, m_M[14]);
HH4<3>(A, B, C, D, m_M[1]);
HH4<9>(D, A, B, C, m_M[9]);
HH4<11>(C, D, A, B, m_M[5]);
HH4<15>(B, C, D, A, m_M[13]);
HH4<3>(A, B, C, D, m_M[3]);
HH4<9>(D, A, B, C, m_M[11]);
HH4<11>(C, D, A, B, m_M[7]);
HH4<15>(B, C, D, A, m_M[15]);
A = (m_digest[0] += A);
B = (m_digest[1] += B);
C = (m_digest[2] += C);
D = (m_digest[3] += D);
input += hash_block_size();
}
}
#pragma clang diagnostic pop
/*
* Copy out the digest
*/
void MD4::copy_out(uint8_t output[]) {
copy_out_vec_le(output, output_length(), m_digest);
}
/*
* Clear memory of sensitive data
*/
void MD4::clear() {
MDx_HashFunction::clear();
m_digest[0] = 0x67452301;
m_digest[1] = 0xEFCDAB89;
m_digest[2] = 0x98BADCFE;
m_digest[3] = 0x10325476;
}
然后这就勾起了我的好奇心,为什么作者对于md4和md5的实现的方法大相径庭,然后我先看了下这这两部分的作者,发现提交者都是一位,并且时间也是相同的。
这就很迷了,为什么作者会选择两种实现方案呢,实话说到本文之前我是没想明白,如果读者大佬们有什么好的看法,也欢迎和我交流。
好了,有关于md4的具体的压缩函数的设计,可以去参考下相关rfc或者我之前写过的文章,在这里不在展开来讲了。
RIPEMD-160
这个对于压缩函数的实现,看看起来就比较中规中矩了,目前没发现比较特别的写法,因此呢在这里不展开来聊了,有兴趣的读者可以自行阅读一下细节,在这里贴心的贴一下代码,防止读者不想打开对应的源码(才不是为了凑字数)。
/*
* RIPEMD-160
* (C) 1999-2007 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/internal/rmd160.h>
#include <botan/internal/loadstor.h>
#include <botan/internal/rotate.h>
#include <botan/internal/bit_ops.h>
namespace Botan {
namespace {
/*
* RIPEMD-160 F1 Function
*/
template<size_t S>
inline void F1(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E,
uint32_t M)
{
A += (B ^ C ^ D) + M;
A = rotl<S>(A) + E;
C = rotl<10>(C);
}
/*
* RIPEMD-160 F2 Function
*/
template<size_t S>
inline void F2(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E,
uint32_t M)
{
A += choose(B, C, D) + M;
A = rotl<S>(A) + E;
C = rotl<10>(C);
}
/*
* RIPEMD-160 F3 Function
*/
template<size_t S>
inline void F3(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E,
uint32_t M)
{
A += (D ^ (B | ~C)) + M;
A = rotl<S>(A) + E;
C = rotl<10>(C);
}
/*
* RIPEMD-160 F4 Function
*/
template<size_t S>
inline void F4(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E,
uint32_t M)
{
A += choose(D, B, C) + M;
A = rotl<S>(A) + E;
C = rotl<10>(C);
}
/*
* RIPEMD-160 F5 Function
*/
template<size_t S>
inline void F5(uint32_t& A, uint32_t B, uint32_t& C, uint32_t D, uint32_t E,
uint32_t M)
{
A += (B ^ (C | ~D)) + M;
A = rotl<S>(A) + E;
C = rotl<10>(C);
}
}
/*
* RIPEMD-160 Compression Function
*/
void RIPEMD_160::compress_n(const uint8_t input[], size_t blocks)
{
const uint32_t MAGIC2 = 0x5A827999, MAGIC3 = 0x6ED9EBA1,
MAGIC4 = 0x8F1BBCDC, MAGIC5 = 0xA953FD4E,
MAGIC6 = 0x50A28BE6, MAGIC7 = 0x5C4DD124,
MAGIC8 = 0x6D703EF3, MAGIC9 = 0x7A6D76E9;
for(size_t i = 0; i != blocks; ++i)
{
load_le(m_M.data(), input, m_M.size());
uint32_t A1 = m_digest[0], A2 = A1,
B1 = m_digest[1], B2 = B1,
C1 = m_digest[2], C2 = C1,
D1 = m_digest[3], D2 = D1,
E1 = m_digest[4], E2 = E1;
F1<11>(A1,B1,C1,D1,E1,m_M[ 0] ); F5< 8>(A2,B2,C2,D2,E2,m_M[ 5]+MAGIC6);
F1<14>(E1,A1,B1,C1,D1,m_M[ 1] ); F5< 9>(E2,A2,B2,C2,D2,m_M[14]+MAGIC6);
F1<15>(D1,E1,A1,B1,C1,m_M[ 2] ); F5< 9>(D2,E2,A2,B2,C2,m_M[ 7]+MAGIC6);
F1<12>(C1,D1,E1,A1,B1,m_M[ 3] ); F5<11>(C2,D2,E2,A2,B2,m_M[ 0]+MAGIC6);
F1< 5>(B1,C1,D1,E1,A1,m_M[ 4] ); F5<13>(B2,C2,D2,E2,A2,m_M[ 9]+MAGIC6);
F1< 8>(A1,B1,C1,D1,E1,m_M[ 5] ); F5<15>(A2,B2,C2,D2,E2,m_M[ 2]+MAGIC6);
F1< 7>(E1,A1,B1,C1,D1,m_M[ 6] ); F5<15>(E2,A2,B2,C2,D2,m_M[11]+MAGIC6);
F1< 9>(D1,E1,A1,B1,C1,m_M[ 7] ); F5< 5>(D2,E2,A2,B2,C2,m_M[ 4]+MAGIC6);
F1<11>(C1,D1,E1,A1,B1,m_M[ 8] ); F5< 7>(C2,D2,E2,A2,B2,m_M[13]+MAGIC6);
F1<13>(B1,C1,D1,E1,A1,m_M[ 9] ); F5< 7>(B2,C2,D2,E2,A2,m_M[ 6]+MAGIC6);
F1<14>(A1,B1,C1,D1,E1,m_M[10] ); F5< 8>(A2,B2,C2,D2,E2,m_M[15]+MAGIC6);
F1<15>(E1,A1,B1,C1,D1,m_M[11] ); F5<11>(E2,A2,B2,C2,D2,m_M[ 8]+MAGIC6);
F1< 6>(D1,E1,A1,B1,C1,m_M[12] ); F5<14>(D2,E2,A2,B2,C2,m_M[ 1]+MAGIC6);
F1< 7>(C1,D1,E1,A1,B1,m_M[13] ); F5<14>(C2,D2,E2,A2,B2,m_M[10]+MAGIC6);
F1< 9>(B1,C1,D1,E1,A1,m_M[14] ); F5<12>(B2,C2,D2,E2,A2,m_M[ 3]+MAGIC6);
F1< 8>(A1,B1,C1,D1,E1,m_M[15] ); F5< 6>(A2,B2,C2,D2,E2,m_M[12]+MAGIC6);
F2< 7>(E1,A1,B1,C1,D1,m_M[ 7]+MAGIC2); F4< 9>(E2,A2,B2,C2,D2,m_M[ 6]+MAGIC7);
F2< 6>(D1,E1,A1,B1,C1,m_M[ 4]+MAGIC2); F4<13>(D2,E2,A2,B2,C2,m_M[11]+MAGIC7);
F2< 8>(C1,D1,E1,A1,B1,m_M[13]+MAGIC2); F4<15>(C2,D2,E2,A2,B2,m_M[ 3]+MAGIC7);
F2<13>(B1,C1,D1,E1,A1,m_M[ 1]+MAGIC2); F4< 7>(B2,C2,D2,E2,A2,m_M[ 7]+MAGIC7);
F2<11>(A1,B1,C1,D1,E1,m_M[10]+MAGIC2); F4<12>(A2,B2,C2,D2,E2,m_M[ 0]+MAGIC7);
F2< 9>(E1,A1,B1,C1,D1,m_M[ 6]+MAGIC2); F4< 8>(E2,A2,B2,C2,D2,m_M[13]+MAGIC7);
F2< 7>(D1,E1,A1,B1,C1,m_M[15]+MAGIC2); F4< 9>(D2,E2,A2,B2,C2,m_M[ 5]+MAGIC7);
F2<15>(C1,D1,E1,A1,B1,m_M[ 3]+MAGIC2); F4<11>(C2,D2,E2,A2,B2,m_M[10]+MAGIC7);
F2< 7>(B1,C1,D1,E1,A1,m_M[12]+MAGIC2); F4< 7>(B2,C2,D2,E2,A2,m_M[14]+MAGIC7);
F2<12>(A1,B1,C1,D1,E1,m_M[ 0]+MAGIC2); F4< 7>(A2,B2,C2,D2,E2,m_M[15]+MAGIC7);
F2<15>(E1,A1,B1,C1,D1,m_M[ 9]+MAGIC2); F4<12>(E2,A2,B2,C2,D2,m_M[ 8]+MAGIC7);
F2< 9>(D1,E1,A1,B1,C1,m_M[ 5]+MAGIC2); F4< 7>(D2,E2,A2,B2,C2,m_M[12]+MAGIC7);
F2<11>(C1,D1,E1,A1,B1,m_M[ 2]+MAGIC2); F4< 6>(C2,D2,E2,A2,B2,m_M[ 4]+MAGIC7);
F2< 7>(B1,C1,D1,E1,A1,m_M[14]+MAGIC2); F4<15>(B2,C2,D2,E2,A2,m_M[ 9]+MAGIC7);
F2<13>(A1,B1,C1,D1,E1,m_M[11]+MAGIC2); F4<13>(A2,B2,C2,D2,E2,m_M[ 1]+MAGIC7);
F2<12>(E1,A1,B1,C1,D1,m_M[ 8]+MAGIC2); F4<11>(E2,A2,B2,C2,D2,m_M[ 2]+MAGIC7);
F3<11>(D1,E1,A1,B1,C1,m_M[ 3]+MAGIC3); F3< 9>(D2,E2,A2,B2,C2,m_M[15]+MAGIC8);
F3<13>(C1,D1,E1,A1,B1,m_M[10]+MAGIC3); F3< 7>(C2,D2,E2,A2,B2,m_M[ 5]+MAGIC8);
F3< 6>(B1,C1,D1,E1,A1,m_M[14]+MAGIC3); F3<15>(B2,C2,D2,E2,A2,m_M[ 1]+MAGIC8);
F3< 7>(A1,B1,C1,D1,E1,m_M[ 4]+MAGIC3); F3<11>(A2,B2,C2,D2,E2,m_M[ 3]+MAGIC8);
F3<14>(E1,A1,B1,C1,D1,m_M[ 9]+MAGIC3); F3< 8>(E2,A2,B2,C2,D2,m_M[ 7]+MAGIC8);
F3< 9>(D1,E1,A1,B1,C1,m_M[15]+MAGIC3); F3< 6>(D2,E2,A2,B2,C2,m_M[14]+MAGIC8);
F3<13>(C1,D1,E1,A1,B1,m_M[ 8]+MAGIC3); F3< 6>(C2,D2,E2,A2,B2,m_M[ 6]+MAGIC8);
F3<15>(B1,C1,D1,E1,A1,m_M[ 1]+MAGIC3); F3<14>(B2,C2,D2,E2,A2,m_M[ 9]+MAGIC8);
F3<14>(A1,B1,C1,D1,E1,m_M[ 2]+MAGIC3); F3<12>(A2,B2,C2,D2,E2,m_M[11]+MAGIC8);
F3< 8>(E1,A1,B1,C1,D1,m_M[ 7]+MAGIC3); F3<13>(E2,A2,B2,C2,D2,m_M[ 8]+MAGIC8);
F3<13>(D1,E1,A1,B1,C1,m_M[ 0]+MAGIC3); F3< 5>(D2,E2,A2,B2,C2,m_M[12]+MAGIC8);
F3< 6>(C1,D1,E1,A1,B1,m_M[ 6]+MAGIC3); F3<14>(C2,D2,E2,A2,B2,m_M[ 2]+MAGIC8);
F3< 5>(B1,C1,D1,E1,A1,m_M[13]+MAGIC3); F3<13>(B2,C2,D2,E2,A2,m_M[10]+MAGIC8);
F3<12>(A1,B1,C1,D1,E1,m_M[11]+MAGIC3); F3<13>(A2,B2,C2,D2,E2,m_M[ 0]+MAGIC8);
F3< 7>(E1,A1,B1,C1,D1,m_M[ 5]+MAGIC3); F3< 7>(E2,A2,B2,C2,D2,m_M[ 4]+MAGIC8);
F3< 5>(D1,E1,A1,B1,C1,m_M[12]+MAGIC3); F3< 5>(D2,E2,A2,B2,C2,m_M[13]+MAGIC8);
F4<11>(C1,D1,E1,A1,B1,m_M[ 1]+MAGIC4); F2<15>(C2,D2,E2,A2,B2,m_M[ 8]+MAGIC9);
F4<12>(B1,C1,D1,E1,A1,m_M[ 9]+MAGIC4); F2< 5>(B2,C2,D2,E2,A2,m_M[ 6]+MAGIC9);
F4<14>(A1,B1,C1,D1,E1,m_M[11]+MAGIC4); F2< 8>(A2,B2,C2,D2,E2,m_M[ 4]+MAGIC9);
F4<15>(E1,A1,B1,C1,D1,m_M[10]+MAGIC4); F2<11>(E2,A2,B2,C2,D2,m_M[ 1]+MAGIC9);
F4<14>(D1,E1,A1,B1,C1,m_M[ 0]+MAGIC4); F2<14>(D2,E2,A2,B2,C2,m_M[ 3]+MAGIC9);
F4<15>(C1,D1,E1,A1,B1,m_M[ 8]+MAGIC4); F2<14>(C2,D2,E2,A2,B2,m_M[11]+MAGIC9);
F4< 9>(B1,C1,D1,E1,A1,m_M[12]+MAGIC4); F2< 6>(B2,C2,D2,E2,A2,m_M[15]+MAGIC9);
F4< 8>(A1,B1,C1,D1,E1,m_M[ 4]+MAGIC4); F2<14>(A2,B2,C2,D2,E2,m_M[ 0]+MAGIC9);
F4< 9>(E1,A1,B1,C1,D1,m_M[13]+MAGIC4); F2< 6>(E2,A2,B2,C2,D2,m_M[ 5]+MAGIC9);
F4<14>(D1,E1,A1,B1,C1,m_M[ 3]+MAGIC4); F2< 9>(D2,E2,A2,B2,C2,m_M[12]+MAGIC9);
F4< 5>(C1,D1,E1,A1,B1,m_M[ 7]+MAGIC4); F2<12>(C2,D2,E2,A2,B2,m_M[ 2]+MAGIC9);
F4< 6>(B1,C1,D1,E1,A1,m_M[15]+MAGIC4); F2< 9>(B2,C2,D2,E2,A2,m_M[13]+MAGIC9);
F4< 8>(A1,B1,C1,D1,E1,m_M[14]+MAGIC4); F2<12>(A2,B2,C2,D2,E2,m_M[ 9]+MAGIC9);
F4< 6>(E1,A1,B1,C1,D1,m_M[ 5]+MAGIC4); F2< 5>(E2,A2,B2,C2,D2,m_M[ 7]+MAGIC9);
F4< 5>(D1,E1,A1,B1,C1,m_M[ 6]+MAGIC4); F2<15>(D2,E2,A2,B2,C2,m_M[10]+MAGIC9);
F4<12>(C1,D1,E1,A1,B1,m_M[ 2]+MAGIC4); F2< 8>(C2,D2,E2,A2,B2,m_M[14]+MAGIC9);
F5< 9>(B1,C1,D1,E1,A1,m_M[ 4]+MAGIC5); F1< 8>(B2,C2,D2,E2,A2,m_M[12] );
F5<15>(A1,B1,C1,D1,E1,m_M[ 0]+MAGIC5); F1< 5>(A2,B2,C2,D2,E2,m_M[15] );
F5< 5>(E1,A1,B1,C1,D1,m_M[ 5]+MAGIC5); F1<12>(E2,A2,B2,C2,D2,m_M[10] );
F5<11>(D1,E1,A1,B1,C1,m_M[ 9]+MAGIC5); F1< 9>(D2,E2,A2,B2,C2,m_M[ 4] );
F5< 6>(C1,D1,E1,A1,B1,m_M[ 7]+MAGIC5); F1<12>(C2,D2,E2,A2,B2,m_M[ 1] );
F5< 8>(B1,C1,D1,E1,A1,m_M[12]+MAGIC5); F1< 5>(B2,C2,D2,E2,A2,m_M[ 5] );
F5<13>(A1,B1,C1,D1,E1,m_M[ 2]+MAGIC5); F1<14>(A2,B2,C2,D2,E2,m_M[ 8] );
F5<12>(E1,A1,B1,C1,D1,m_M[10]+MAGIC5); F1< 6>(E2,A2,B2,C2,D2,m_M[ 7] );
F5< 5>(D1,E1,A1,B1,C1,m_M[14]+MAGIC5); F1< 8>(D2,E2,A2,B2,C2,m_M[ 6] );
F5<12>(C1,D1,E1,A1,B1,m_M[ 1]+MAGIC5); F1<13>(C2,D2,E2,A2,B2,m_M[ 2] );
F5<13>(B1,C1,D1,E1,A1,m_M[ 3]+MAGIC5); F1< 6>(B2,C2,D2,E2,A2,m_M[13] );
F5<14>(A1,B1,C1,D1,E1,m_M[ 8]+MAGIC5); F1< 5>(A2,B2,C2,D2,E2,m_M[14] );
F5<11>(E1,A1,B1,C1,D1,m_M[11]+MAGIC5); F1<15>(E2,A2,B2,C2,D2,m_M[ 0] );
F5< 8>(D1,E1,A1,B1,C1,m_M[ 6]+MAGIC5); F1<13>(D2,E2,A2,B2,C2,m_M[ 3] );
F5< 5>(C1,D1,E1,A1,B1,m_M[15]+MAGIC5); F1<11>(C2,D2,E2,A2,B2,m_M[ 9] );
F5< 6>(B1,C1,D1,E1,A1,m_M[13]+MAGIC5); F1<11>(B2,C2,D2,E2,A2,m_M[11] );
C1 = m_digest[1] + C1 + D2;
m_digest[1] = m_digest[2] + D1 + E2;
m_digest[2] = m_digest[3] + E1 + A2;
m_digest[3] = m_digest[4] + A1 + B2;
m_digest[4] = m_digest[0] + B1 + C2;
m_digest[0] = C1;
input += hash_block_size();
}
}
/*
* Copy out the digest
*/
void RIPEMD_160::copy_out(uint8_t output[])
{
copy_out_vec_le(output, output_length(), m_digest);
}
/*
* Clear memory of sensitive data
*/
void RIPEMD_160::clear()
{
MDx_HashFunction::clear();
zeroise(m_M);
m_digest[0] = 0x67452301;
m_digest[1] = 0xEFCDAB89;
m_digest[2] = 0x98BADCFE;
m_digest[3] = 0x10325476;
m_digest[4] = 0xC3D2E1F0;
}
}
SHA1
我们接着来看下一个md结构的的哈希函数,这个就不展开讲具体的压缩函数的设计了,说一下这块和之前我们看过的md5以及md4的一个不同,我们来看一下头文件,这里多了一个汇编的写法,如果是开启了对应的处理器指令,则会走对应的汇编,由于汇编不再本系列源码解析的范畴之内,因此呢咱们直接去看对应的软件实现,所以后文如果牵扯到有关汇编的写法,这里会直接给略过,不再展开来讲了。
// 路径: src/lib/hash/sha1/sha160.h
/*
* SHA-160
* (C) 1999-2007,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#ifndef BOTAN_SHA_160_H_
#define BOTAN_SHA_160_H_
#include <botan/internal/mdx_hash.h>
namespace Botan {
/**
* NIST's SHA-160
*/
class SHA_160 final : public MDx_HashFunction
{
public:
std::string name() const override { return "SHA-160"; }
size_t output_length() const override { return 20; }
std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<SHA_160>(); }
std::unique_ptr<HashFunction> copy_state() const override;
void clear() override;
SHA_160() : MDx_HashFunction(64, true, true), m_digest(5)
{
clear();
}
private:
void compress_n(const uint8_t[], size_t blocks) override;
// 这里因为有了汇编的写法,因此如果开启汇编的话,会走汇编的流程
#if defined(BOTAN_HAS_SHA1_ARMV8)
static void sha1_armv8_compress_n(secure_vector<uint32_t>& digest,
const uint8_t blocks[],
size_t block_count);
#endif
#if defined(BOTAN_HAS_SHA1_SSE2)
static void sse2_compress_n(secure_vector<uint32_t>& digest,
const uint8_t blocks[],
size_t block_count);
#endif
#if defined(BOTAN_HAS_SHA1_X86_SHA_NI)
// Using x86 SHA instructions in Intel Goldmont and Cannonlake
static void sha1_compress_x86(secure_vector<uint32_t>& digest,
const uint8_t blocks[],
size_t block_count);
#endif
void copy_out(uint8_t[]) override;
/**
* The digest value
*/
secure_vector<uint32_t> m_digest;
/**
* The message buffer
*/
secure_vector<uint32_t> m_W;
};
typedef SHA_160 SHA_1;
}
#endif
剩下的就不介绍了,压缩函数具体的内容在源码阅读当中就不展开来讲了,不熟悉的读者可以参考rfc
SHA2
熟悉sha2系列算法的读者应该清楚,对于sha2系列算法可以根据输出长度分为两类,第一类是SHA224和SHA256,第二类是SHA384和SHA512,他们所采用的缓冲区的大小不同,前者是32位后者是64位,因此我们可以看到在botan对于这个的实现当中也是分为两类来实现的,因为本身的结构是一样的,只不过是buffer和表以及初始化向量有所不同,因此呢,咱们只以32位为例来看一下,对于64位实际上和32位的代码是几乎一样的。
/*
* SHA-{224,256}
* (C) 1999-2011 Jack Lloyd
* 2007 FlexSecure GmbH
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#ifndef BOTAN_SHA_224_256_H_
#define BOTAN_SHA_224_256_H_
#include <botan/internal/mdx_hash.h>
namespace Botan {
/**
* SHA-224
*/
class SHA_224 final : public MDx_HashFunction
{
public:
std::string name() const override { return "SHA-224"; }
size_t output_length() const override { return 28; }
std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<SHA_224>(); }
std::unique_ptr<HashFunction> copy_state() const override;
void clear() override;
std::string provider() const override;
SHA_224() : MDx_HashFunction(64, true, true), m_digest(8)
{ clear(); }
private:
void compress_n(const uint8_t[], size_t blocks) override;
void copy_out(uint8_t[]) override;
secure_vector<uint32_t> m_digest;
};
/**
* SHA-256
*/
class SHA_256 final : public MDx_HashFunction
{
public:
std::string name() const override { return "SHA-256"; }
size_t output_length() const override { return 32; }
std::unique_ptr<HashFunction> new_object() const override { return std::make_unique<SHA_256>(); }
std::unique_ptr<HashFunction> copy_state() const override;
void clear() override;
std::string provider() const override;
SHA_256() : MDx_HashFunction(64, true, true), m_digest(8)
{ clear(); }
/*
* Perform a SHA-256 compression. For internal use
* 实际上在SHA224内部调用的也是这一个函数
*/
static void compress_digest(secure_vector<uint32_t>& digest,
const uint8_t input[],
size_t blocks);
private:
void compress_n(const uint8_t[], size_t blocks) override;
void copy_out(uint8_t[]) override;
secure_vector<uint32_t> m_digest;
};
}
#endif
我们可以看到,在这个头文件当中SHA224和SHA256是写在一起的,然后相比于我们之前所看到的哈希函数,这个多了一个私有的函数 compress_digest
,这个函数实际上是执行压缩函数的地方,我们可以看到无论是SHA224还是SHA256调用的都是他。
/*
* SHA-224 compression function
*/
void SHA_224::compress_n(const uint8_t input[], size_t blocks)
{
SHA_256::compress_digest(m_digest, input, blocks);
}
/*
* SHA-256 compression function
*/
void SHA_256::compress_n(const uint8_t input[], size_t blocks)
{
SHA_256::compress_digest(m_digest, input, blocks);
}
这里对于实际的压缩函数的处理,和其他的有一些不太一样,这里用了一个宏,就把所有的整个处理函数写到一起了。
/*
* SHA-256 F1 Function
*
* Use a macro as many compilers won't inline a function this big,
* even though it is much faster if inlined.
*/
#define SHA2_32_F(A, B, C, D, E, F, G, H, M1, M2, M3, M4, magic) do {
uint32_t A_rho = rotr<2>(A) ^ rotr<13>(A) ^ rotr<22>(A);
uint32_t E_rho = rotr<6>(E) ^ rotr<11>(E) ^ rotr<25>(E);
uint32_t M2_sigma = rotr<17>(M2) ^ rotr<19>(M2) ^ (M2 >> 10);
uint32_t M4_sigma = rotr<7>(M4) ^ rotr<18>(M4) ^ (M4 >> 3);
H += magic + E_rho + choose(E, F, G) + M1;
D += H;
H += A_rho + majority(A, B, C);
M1 += M2_sigma + M3 + M4_sigma;
} while(0);
我们知道,实际上宏是对代码的一个直接替换,然后作者也解释这么搞的原因了,因为大多数的编译器都无法内联这么大的函数,尽管是内联的速度要快,因此这里用宏来替代了,这是个和我们之前所看到的前面的几个算法的一个不同。
SM3
接下来,我们再来看一下,这个密码库居然实现了国密算法,给个好评,这个的写法和MD4在风格上有一些相似。
/*
* SM3
* (C) 2017 Ribose Inc.
* (C) 2021 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/internal/sm3.h>
#include <botan/internal/loadstor.h>
#include <botan/internal/rotate.h>
#include <botan/internal/bit_ops.h>
namespace Botan {
namespace {
const uint32_t SM3_IV[] = {
0x7380166fUL, 0x4914b2b9UL, 0x172442d7UL, 0xda8a0600UL,
0xa96f30bcUL, 0x163138aaUL, 0xe38dee4dUL, 0xb0fb0e4eUL
};
inline uint32_t P0(uint32_t X)
{
return X ^ rotl<9>(X) ^ rotl<17>(X);
}
inline void R1(uint32_t A, uint32_t& B, uint32_t C, uint32_t& D,
uint32_t E, uint32_t& F, uint32_t G, uint32_t& H,
uint32_t TJ, uint32_t Wi, uint32_t Wj)
{
const uint32_t A12 = rotl<12>(A);
const uint32_t SS1 = rotl<7>(A12 + E + TJ);
const uint32_t TT1 = (A ^ B ^ C) + D + (SS1 ^ A12) + Wj;
const uint32_t TT2 = (E ^ F ^ G) + H + SS1 + Wi;
B = rotl<9>(B);
D = TT1;
F = rotl<19>(F);
H = P0(TT2);
}
inline void R2(uint32_t A, uint32_t& B, uint32_t C, uint32_t& D,
uint32_t E, uint32_t& F, uint32_t G, uint32_t& H,
uint32_t TJ, uint32_t Wi, uint32_t Wj)
{
const uint32_t A12 = rotl<12>(A);
const uint32_t SS1 = rotl<7>(A12 + E + TJ);
const uint32_t TT1 = majority(A, B, C) + D + (SS1 ^ A12) + Wj;
const uint32_t TT2 = choose(E, F, G) + H + SS1 + Wi;
B = rotl<9>(B);
D = TT1;
F = rotl<19>(F);
H = P0(TT2);
}
inline uint32_t P1(uint32_t X)
{
return X ^ rotl<15>(X) ^ rotl<23>(X);
}
inline uint32_t SM3_E(uint32_t W0, uint32_t W7, uint32_t W13, uint32_t W3, uint32_t W10)
{
return P1(W0 ^ W7 ^ rotl<15>(W13)) ^ rotl<7>(W3) ^ W10;
}
}
/*
* SM3 Compression Function
*/
void SM3::compress_n(const uint8_t input[], size_t blocks)
{
uint32_t A = m_digest[0], B = m_digest[1], C = m_digest[2], D = m_digest[3],
E = m_digest[4], F = m_digest[5], G = m_digest[6], H = m_digest[7];
for(size_t i = 0; i != blocks; ++i)
{
uint32_t W00 = load_be<uint32_t>(input, 0);
uint32_t W01 = load_be<uint32_t>(input, 1);
uint32_t W02 = load_be<uint32_t>(input, 2);
uint32_t W03 = load_be<uint32_t>(input, 3);
uint32_t W04 = load_be<uint32_t>(input, 4);
uint32_t W05 = load_be<uint32_t>(input, 5);
uint32_t W06 = load_be<uint32_t>(input, 6);
uint32_t W07 = load_be<uint32_t>(input, 7);
uint32_t W08 = load_be<uint32_t>(input, 8);
uint32_t W09 = load_be<uint32_t>(input, 9);
uint32_t W10 = load_be<uint32_t>(input, 10);
uint32_t W11 = load_be<uint32_t>(input, 11);
uint32_t W12 = load_be<uint32_t>(input, 12);
uint32_t W13 = load_be<uint32_t>(input, 13);
uint32_t W14 = load_be<uint32_t>(input, 14);
uint32_t W15 = load_be<uint32_t>(input, 15);
R1(A, B, C, D, E, F, G, H, 0x79CC4519, W00, W00 ^ W04);
W00 = SM3_E(W00, W07, W13, W03, W10);
R1(D, A, B, C, H, E, F, G, 0xF3988A32, W01, W01 ^ W05);
W01 = SM3_E(W01, W08, W14, W04, W11);
R1(C, D, A, B, G, H, E, F, 0xE7311465, W02, W02 ^ W06);
W02 = SM3_E(W02, W09, W15, W05, W12);
R1(B, C, D, A, F, G, H, E, 0xCE6228CB, W03, W03 ^ W07);
W03 = SM3_E(W03, W10, W00, W06, W13);
R1(A, B, C, D, E, F, G, H, 0x9CC45197, W04, W04 ^ W08);
W04 = SM3_E(W04, W11, W01, W07, W14);
R1(D, A, B, C, H, E, F, G, 0x3988A32F, W05, W05 ^ W09);
W05 = SM3_E(W05, W12, W02, W08, W15);
R1(C, D, A, B, G, H, E, F, 0x7311465E, W06, W06 ^ W10);
W06 = SM3_E(W06, W13, W03, W09, W00);
R1(B, C, D, A, F, G, H, E, 0xE6228CBC, W07, W07 ^ W11);
W07 = SM3_E(W07, W14, W04, W10, W01);
R1(A, B, C, D, E, F, G, H, 0xCC451979, W08, W08 ^ W12);
W08 = SM3_E(W08, W15, W05, W11, W02);
R1(D, A, B, C, H, E, F, G, 0x988A32F3, W09, W09 ^ W13);
W09 = SM3_E(W09, W00, W06, W12, W03);
R1(C, D, A, B, G, H, E, F, 0x311465E7, W10, W10 ^ W14);
W10 = SM3_E(W10, W01, W07, W13, W04);
R1(B, C, D, A, F, G, H, E, 0x6228CBCE, W11, W11 ^ W15);
W11 = SM3_E(W11, W02, W08, W14, W05);
R1(A, B, C, D, E, F, G, H, 0xC451979C, W12, W12 ^ W00);
W12 = SM3_E(W12, W03, W09, W15, W06);
R1(D, A, B, C, H, E, F, G, 0x88A32F39, W13, W13 ^ W01);
W13 = SM3_E(W13, W04, W10, W00, W07);
R1(C, D, A, B, G, H, E, F, 0x11465E73, W14, W14 ^ W02);
W14 = SM3_E(W14, W05, W11, W01, W08);
R1(B, C, D, A, F, G, H, E, 0x228CBCE6, W15, W15 ^ W03);
W15 = SM3_E(W15, W06, W12, W02, W09);
R2(A, B, C, D, E, F, G, H, 0x9D8A7A87, W00, W00 ^ W04);
W00 = SM3_E(W00, W07, W13, W03, W10);
R2(D, A, B, C, H, E, F, G, 0x3B14F50F, W01, W01 ^ W05);
W01 = SM3_E(W01, W08, W14, W04, W11);
R2(C, D, A, B, G, H, E, F, 0x7629EA1E, W02, W02 ^ W06);
W02 = SM3_E(W02, W09, W15, W05, W12);
R2(B, C, D, A, F, G, H, E, 0xEC53D43C, W03, W03 ^ W07);
W03 = SM3_E(W03, W10, W00, W06, W13);
R2(A, B, C, D, E, F, G, H, 0xD8A7A879, W04, W04 ^ W08);
W04 = SM3_E(W04, W11, W01, W07, W14);
R2(D, A, B, C, H, E, F, G, 0xB14F50F3, W05, W05 ^ W09);
W05 = SM3_E(W05, W12, W02, W08, W15);
R2(C, D, A, B, G, H, E, F, 0x629EA1E7, W06, W06 ^ W10);
W06 = SM3_E(W06, W13, W03, W09, W00);
R2(B, C, D, A, F, G, H, E, 0xC53D43CE, W07, W07 ^ W11);
W07 = SM3_E(W07, W14, W04, W10, W01);
R2(A, B, C, D, E, F, G, H, 0x8A7A879D, W08, W08 ^ W12);
W08 = SM3_E(W08, W15, W05, W11, W02);
R2(D, A, B, C, H, E, F, G, 0x14F50F3B, W09, W09 ^ W13);
W09 = SM3_E(W09, W00, W06, W12, W03);
R2(C, D, A, B, G, H, E, F, 0x29EA1E76, W10, W10 ^ W14);
W10 = SM3_E(W10, W01, W07, W13, W04);
R2(B, C, D, A, F, G, H, E, 0x53D43CEC, W11, W11 ^ W15);
W11 = SM3_E(W11, W02, W08, W14, W05);
R2(A, B, C, D, E, F, G, H, 0xA7A879D8, W12, W12 ^ W00);
W12 = SM3_E(W12, W03, W09, W15, W06);
R2(D, A, B, C, H, E, F, G, 0x4F50F3B1, W13, W13 ^ W01);
W13 = SM3_E(W13, W04, W10, W00, W07);
R2(C, D, A, B, G, H, E, F, 0x9EA1E762, W14, W14 ^ W02);
W14 = SM3_E(W14, W05, W11, W01, W08);
R2(B, C, D, A, F, G, H, E, 0x3D43CEC5, W15, W15 ^ W03);
W15 = SM3_E(W15, W06, W12, W02, W09);
R2(A, B, C, D, E, F, G, H, 0x7A879D8A, W00, W00 ^ W04);
W00 = SM3_E(W00, W07, W13, W03, W10);
R2(D, A, B, C, H, E, F, G, 0xF50F3B14, W01, W01 ^ W05);
W01 = SM3_E(W01, W08, W14, W04, W11);
R2(C, D, A, B, G, H, E, F, 0xEA1E7629, W02, W02 ^ W06);
W02 = SM3_E(W02, W09, W15, W05, W12);
R2(B, C, D, A, F, G, H, E, 0xD43CEC53, W03, W03 ^ W07);
W03 = SM3_E(W03, W10, W00, W06, W13);
R2(A, B, C, D, E, F, G, H, 0xA879D8A7, W04, W04 ^ W08);
W04 = SM3_E(W04, W11, W01, W07, W14);
R2(D, A, B, C, H, E, F, G, 0x50F3B14F, W05, W05 ^ W09);
W05 = SM3_E(W05, W12, W02, W08, W15);
R2(C, D, A, B, G, H, E, F, 0xA1E7629E, W06, W06 ^ W10);
W06 = SM3_E(W06, W13, W03, W09, W00);
R2(B, C, D, A, F, G, H, E, 0x43CEC53D, W07, W07 ^ W11);
W07 = SM3_E(W07, W14, W04, W10, W01);
R2(A, B, C, D, E, F, G, H, 0x879D8A7A, W08, W08 ^ W12);
W08 = SM3_E(W08, W15, W05, W11, W02);
R2(D, A, B, C, H, E, F, G, 0x0F3B14F5, W09, W09 ^ W13);
W09 = SM3_E(W09, W00, W06, W12, W03);
R2(C, D, A, B, G, H, E, F, 0x1E7629EA, W10, W10 ^ W14);
W10 = SM3_E(W10, W01, W07, W13, W04);
R2(B, C, D, A, F, G, H, E, 0x3CEC53D4, W11, W11 ^ W15);
W11 = SM3_E(W11, W02, W08, W14, W05);
R2(A, B, C, D, E, F, G, H, 0x79D8A7A8, W12, W12 ^ W00);
W12 = SM3_E(W12, W03, W09, W15, W06);
R2(D, A, B, C, H, E, F, G, 0xF3B14F50, W13, W13 ^ W01);
W13 = SM3_E(W13, W04, W10, W00, W07);
R2(C, D, A, B, G, H, E, F, 0xE7629EA1, W14, W14 ^ W02);
W14 = SM3_E(W14, W05, W11, W01, W08);
R2(B, C, D, A, F, G, H, E, 0xCEC53D43, W15, W15 ^ W03);
W15 = SM3_E(W15, W06, W12, W02, W09);
R2(A, B, C, D, E, F, G, H, 0x9D8A7A87, W00, W00 ^ W04);
W00 = SM3_E(W00, W07, W13, W03, W10);
R2(D, A, B, C, H, E, F, G, 0x3B14F50F, W01, W01 ^ W05);
W01 = SM3_E(W01, W08, W14, W04, W11);
R2(C, D, A, B, G, H, E, F, 0x7629EA1E, W02, W02 ^ W06);
W02 = SM3_E(W02, W09, W15, W05, W12);
R2(B, C, D, A, F, G, H, E, 0xEC53D43C, W03, W03 ^ W07);
W03 = SM3_E(W03, W10, W00, W06, W13);
R2(A, B, C, D, E, F, G, H, 0xD8A7A879, W04, W04 ^ W08);
R2(D, A, B, C, H, E, F, G, 0xB14F50F3, W05, W05 ^ W09);
R2(C, D, A, B, G, H, E, F, 0x629EA1E7, W06, W06 ^ W10);
R2(B, C, D, A, F, G, H, E, 0xC53D43CE, W07, W07 ^ W11);
R2(A, B, C, D, E, F, G, H, 0x8A7A879D, W08, W08 ^ W12);
R2(D, A, B, C, H, E, F, G, 0x14F50F3B, W09, W09 ^ W13);
R2(C, D, A, B, G, H, E, F, 0x29EA1E76, W10, W10 ^ W14);
R2(B, C, D, A, F, G, H, E, 0x53D43CEC, W11, W11 ^ W15);
R2(A, B, C, D, E, F, G, H, 0xA7A879D8, W12, W12 ^ W00);
R2(D, A, B, C, H, E, F, G, 0x4F50F3B1, W13, W13 ^ W01);
R2(C, D, A, B, G, H, E, F, 0x9EA1E762, W14, W14 ^ W02);
R2(B, C, D, A, F, G, H, E, 0x3D43CEC5, W15, W15 ^ W03);
A = (m_digest[0] ^= A);
B = (m_digest[1] ^= B);
C = (m_digest[2] ^= C);
D = (m_digest[3] ^= D);
E = (m_digest[4] ^= E);
F = (m_digest[5] ^= F);
G = (m_digest[6] ^= G);
H = (m_digest[7] ^= H);
input += hash_block_size();
}
}
/*
* Copy out the digest
*/
void SM3::copy_out(uint8_t output[])
{
copy_out_vec_be(output, output_length(), m_digest);
}
/*
* Clear memory of sensitive data
*/
void SM3::clear()
{
MDx_HashFunction::clear();
std::copy(std::begin(SM3_IV), std::end(SM3_IV), m_digest.begin());
}
}
虽然有一些疑惑,但是吧实现起来也没啥毛病,对于SM3的初始化向量东西也不多啊,这为啥前面都是写的固定值,到了这里用了个std里面的copy函数,真的惊了,然后看了一眼,这俩作者不是同一位大佬,哈哈,其实看看这些源码有时候发现欢乐还是蛮多的。
Whirlpool
这一个算法呢比较特殊,虽然他也是Merkle-Damgård 结构的哈希函数,但是呢,如果按照标准实现来看botan源码当中的实现,你会发现,这。。。这还是原来的那个算法吗,如果你能理解之前AES的查表法的话,再返回来看这个的源码实现,就会发现清晰不少,在这里呢,本文的重点不在于每个具体的哈希函数的解析上,因此在这里就不去展开来聊这个的实现细节了,顺道在这里给自己挖一个坑,感觉自己好像是挖了不少的坑,还有好多还没填,不过不要紧,先挖了再说,等着来一篇文章来写一下botan源码当中whirlpool的实现,单独来聊聊这件事中,溜了溜啦。
结束语
本篇文章其实讲的比较水,开始写这一系列的文章,本以为可能会写比较多的内容,但是发现呢,事实并不是这样,还是因为本身密码学相关库的一个特殊性,因为密码算法本身是比较分散的,他们之间的独立性不是特别的强,而且每个密码算法里面涉及到的结构有都是相对独立的,因此呢感觉写着写着就没什么可写的情况,有点难受啊,所以这个系列目前可能,大概率,也许会搁浅一段时间,等我想想有没有什么好的思路来去讲这个的源码,需要考虑的点主要有两个,第一个是如何权衡细节和整体代码分析的一个权重,如果过分去关注细节,那么就和直接去聊某个特定算法是一样的了,如果不去看细节,有些算法的实现中会有一些的小trick,和一些变形的技巧,和我们在教科书当中学到的不是完全一致的,这可能会导致读者的疑惑,哎,太难了,第二个就是密码学库里面的关联性实在是不强,这有好处,也有坏处,好处就是我们可以随便找一个算法来看,不用太关注其他文件下面的东西,坏处就是没什么关联性,也就没什么顺序和逻辑可言了,蓝瘦香菇,我在结束语又啰嗦这么半天,其实目的就一个,这个系列暂时要咕咕一段时间了,咱们有缘再见 ~~。
参考资料
-
https://datatracker.ietf.org/doc/html/rfc1320[1]
Reference
https://datatracker.ietf.org/doc/html/rfc1320: https://datatracker.ietf.org/doc/html/rfc1320
原文始发于微信公众号(Coder小Q):【botan源码阅读】MD结构源码阅读
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论