//BASE的编码、解码
// basecode.cpp - written and placed in thepublic domain by Wei Dai
#include "pch.h"
#ifndef CRYPTOPP_IMPORTS
#include "basecode.h"
#include "fltrimpl.h"
#include
NAMESPACE_BEGIN(CryptoPP)
//编码类的独立初始化,传入参数集
void BaseN_Encoder::IsolatedInitialize(constNameValuePairs ¶meters)
{
//参数集对象的初始化
//classCRYPTOPP_NO_VTABLE NameValuePairs
parameters.GetRequiredParameter("BaseN_Encoder",Name::EncodingLookupArray(), m_alphabet);
parameters.GetRequiredIntParameter("BaseN_Encoder",Name::Log2Base(), m_bitsPerChar);
//m_bitsPerChar为一次参与BASE编码的2进制位数,必须在1-7之间
if (m_bitsPerChar <= 0 || m_bitsPerChar >=8)
throwInvalidArgument("BaseN_Encoder: Log2Base must be between 1 and 7inclusive");
//填充符
byte padding;
bool pad;
if (parameters.GetValue(Name::PaddingByte(),padding))
pad =parameters.GetValueWithDefault(Name::Pad(), true);
else
pad = false;
m_padding = pad ? padding : -1;
m_bytePos = m_bitPos =0;
//计算输出缓冲区大小(BYTE为单位),并申请缓冲区
//因为以8位为单位,所以凑成能被BASE基数的位数m_bitsPerChar整除的最小数
int i = 8;
while (i%m_bitsPerChar != 0)
i += 8;
//计算缓冲区大小,以字节为单位
m_outputBlockSize = i/m_bitsPerChar;
//申请缓冲区
m_outBuf.New(m_outputBlockSize);
}
//BASEN的编码函数(如BASE64、BASE32等等)
size_t BaseN_Encoder::Put2(const byte *begin,size_t length, int messageEnd, bool blocking)
{
FILTER_BEGIN;
while (m_inputPosition < length)
//while (m_inputPosition< length)开始
{
if (m_bytePos ==0)
//初始化输出缓冲区全部置0,以开始新一轮
memset(m_outBuf,0, m_outputBlockSize);
{
//m_inputPosition移一个字节,取编码源流begin中的当前需要处理位置的字节b
//开始新一轮处理,以将该字节处理后所余下位数不够处理或正好处理完毕为一轮
//注意unsignedint在32位系统中,有32位大小,但m_inputPosition
//以一个字节为单位移动
unsignedint b = begin[m_inputPosition++], bitsLeftInSource = 8;
//bitsLeftInSource为源本次需要处理的位数,初值为8
//在b中以BASE基数的位数为单位扩展后填充8位缓冲区=====begin
//处理源和目标,将源以BASE基数要求的位数为单位拆开后,放入输出缓冲区
//的每个字节内,如BASE64则把源二进制流以6位为单位,放入每个字节中,
//一个字节还有2位暂时没用到,从源二进制流中每次取8位进行处理,这
//是必要的,因为要以字节为单位访问内存
while(true)
//while(true)循环开始
{
//确保m_bitPos在BASE基数位数之内
assert(m_bitPos < m_bitsPerChar);
//m_bitPos为上次应处理但未处理只能移交本次处理的位数,因为上次位数
//太少无法处理,如:BASE64,第一次顺利处理6位;第二次要处理2位,因为
//每次必须处理6位,所以第二次将b中2位移至最左边;然后,将b右移8-6=2
//位保存在m_outBuf[m_bytePos]中,然后进行判断发现无法完成处理,只能
//在第三次从begin取一个字节放入b中,读入b中的最左4位新的二进制,
//放入m_outBuf[m_bytePos]的最右边。
//m_bitsPerChar为BASE的基数(如BASE64为6),即每个字母代表几位二进制数
//bitsLeftInTarget为输出缓冲区本次能够接受的位数,也是源本次能够处理的位数
//bitsLeftInSource为源本次需要处理的位数
//因为上次几位无法处理,所以需要本次一起处理
unsignedint bitsLeftInTarget = m_bitsPerChar-m_bitPos;
//输出缓冲区为m_outBuf,大小为m_outputBlockSize字节
//m_bytePos为输出目标当前位置(以字节为单位)
//m_outBuf是个字节为单位的块
//操作为:从b的左边开始,取bitsLeftInTarget
//将输出缓冲区m_outBuf的当前字节的后bitsLeftInTarget位(如BASE64为后6位)
//设为源的当前字节b能够处理的二进制数(如BASE64为6位二进制数)
//b为当前需要处理的源数据,先处理输出缓冲区
m_outBuf[m_bytePos]|= b >> (8-bitsLeftInTarget);//b本身没未改变
//再进行判断,原因是上次无法处理的几位先给予m_outBuf[m_bytePos],以免丢失
if(bitsLeftInSource >= bitsLeftInTarget)
{
//源本次需要处理的位数大于或等于输出缓冲区本次能够接受的位数,即
//有几位本次未能处理完毕或者正好已经处理完了
//如:BASE64,第一次处理时源肯定还有2位没有处理
//m_bitPos置0,因为当前位能顺利处理完,不需要移交给下次处理
m_bitPos = 0;
//当前bitsLeftInTarget位处理完毕,输出缓冲区进入
//下一字节进行下次处理
++m_bytePos;
//更新下次源需要处理的位数为源本次没有处理完的位数
bitsLeftInSource-= bitsLeftInTarget;
if (bitsLeftInSource== 0)
//下次源需要处理的位数为0,退出while(true)循环,进行BASE编码
break;
//将已经处理的位左移出b,仅留未处理的位以给下次处理
b<<= bitsLeftInTarget;
//使用0xff掩码,只保留b的右8位,因为b有32位
b&= 0xff;
}
else
{
//源本次需要处理的位数小于输出缓冲区本次能够接受的位数,不能进行处理
//说明源的本次位数太少,满足不了输出缓冲区接收的需要,读入新的二进制流
//bitsLeftInSource位需要移交给下次处理,更新源的未能处理的位数
//将m_bitPos设为源本次未处理位数m_bitPos加本次需要处理但不能进行处
//理的位数。m_bytePos不能改变,因为m_outBuf[m_bytePos]还有几位没处理完
m_bitPos+= bitsLeftInSource;
//退出while(true)循环
break;
}
}
}
//while(true)结束
//在b中以BASE基数的位数为单位扩展后填充8位缓冲区=====end
//确保缓冲区的当前位置是在缓冲区容量之内
assert(m_bytePos <=m_outputBlockSize);
//如果源已经读完且缓冲区填充完毕,进行BASE转换=====begin
//有种情况在下一步考虑,就是:缓冲区没有填充完,但是源已经读完
if (m_bytePos == m_outputBlockSize)
{
//输出缓冲区已经填充完毕
//注意此时输出缓冲区内仅为待转换为字母表中相关字母的数,
//如BASE64,则仅为1-64之间的数。
inti;
//下面的循环条件为什么不是i<=m_bytePos,原因在于
//缓冲区的大小是BASE基数位数的倍数,所以只要缓冲区能填充满
//最后一定正好遇到下次源需要处理的位数为0,退出while(true)
//循环的情况而退出,但++m_bytePos在退出前就已经执行。
for (i=0;i
{
//确保输出缓冲区每个数都在BASE基数所能表达的最大范围内
assert(m_outBuf[i]< (1 << m_bitsPerChar));
//进行编码转换
m_outBuf[i]= m_alphabet[m_outBuf[i]];
}
//输出缓冲区内容
FILTER_OUTPUT(1,m_outBuf, m_outputBlockSize, 0);
m_bytePos =m_bitPos = 0;//m_bytePos设为0后,可激活生成新的缓冲区
}
//如果缓冲区填充完毕,进行BASE转换=====end
}//while(m_inputPosition < length)结束,至此完成源的BASE编码
//m_inputPosition==length时,源全部读取完毕,需要加消息尾部
if (messageEnd)
{
//处理消息尾部的填充符
if (m_bitPos > 0)
//结束时,源中还有余位,证明属于缓冲区未填满就已经源已经读完,而此时
//++m_bytePos必须补上,因为后面的for循环不是i<=m_bytePos
++m_bytePos;
//缓冲区没有填充完,但是源已经读完
//将缓冲区中的源转换
int i;
for (i=0; i
m_outBuf[i] =m_alphabet[m_outBuf[i]];
//如果有填充符且源中还有余位
if(m_padding != -1 && m_bytePos > 0)
{
memset(m_outBuf+m_bytePos,m_padding, m_outputBlockSize-m_bytePos);
m_bytePos =m_outputBlockSize;
}
//将缓冲区内容输出
FILTER_OUTPUT(2, m_outBuf,m_bytePos, messageEnd);
m_bytePos = m_bitPos = 0;
}
FILTER_END_NO_MESSAGE_END;
}
//解码类的独立初始化
void BaseN_Decoder::IsolatedInitialize(constNameValuePairs ¶meters)
{
//参数集初始化
parameters.GetRequiredParameter("BaseN_Decoder",N
ame::DecodingLookupArray(),m_lookup);
parameters.GetRequiredIntParameter("BaseN_Decoder",Name::Log2Base(), m_bitsPerChar);
if (m_bitsPerChar <= 0 || m_bitsPerChar >=8)
throwInvalidArgument("BaseN_Decoder: Log2Base must be between 1 and 7inclusive");
m_bytePos = m_bitPos =0;
//计算缓冲区大小
int i = m_bitsPerChar;
while (i%8 != 0)
i += m_bitsPerChar;
m_outputBlockSize = i/8;
m_outBuf.New(m_outputBlockSize);
}
//BASE解码函数
size_t BaseN_Decoder::Put2(const byte *begin,size_t length, int messageEnd, bool blocking)
{
FILTER_BEGIN;
//while(m_inputPosition <length)==begin
while(m_inputPosition < length)
{
//m_inputPosition为当前位置,length为源总长度
unsigned int value;
//取源的当前字节所指向的字母代表的整数,m_lookup为字母表的反查表
//m_lookup的声明:constint *m_lookup。将BASE解码后的值取到value中
value =m_lookup[begin[m_inputPosition++]];
//当BASE的基数为7位,字母能代表最大的整数小于256
if(value >= 256)
continue;
if (m_bytePos == 0&& m_bitPos == 0)//申请新缓冲区
memset(m_outBuf,0, m_outputBlockSize);
//粘的工作涉及到2个字节,缓冲区第二个字节填充value的移位位数
//的计算为16-newBitPos如上图所示,将前2个字节的(n+n)位粘
//在一起,一定在第2个字节内空出16-newBitPos位,这也是移位位数
{
//m_bitbos为m_outBuf当前已经填充了字节的位数
//newBitPos为m_outBuf当前字节已经填充的位数与本次需要BASE基数
//的位数之和,实际意义在于检测当前字节还余下多少空间,是否能容
//下需要处理的位数
//m_bitsPerChar为BASE基数的位数
int newBitPos= m_bitPos + m_bitsPerChar;
if(newBitPos <= 8)
//当前字节余下的空间能满足本次需要处理的位数,可以继续处理
m_outBuf[m_bytePos]|= value << (8-newBitPos);
else
{
//当前字节余下的空间不能容下本次需要处理的位数,需要分次在m_outBuf的
//当前字节和下一字节的空间处理,即粘
//第一次先取填充value的左边,直至把当前字节余下的空间填满为止
m_outBuf[m_bytePos] |= value >>(newBitPos-8);
//第一次先取填充value的右边,把右边部分放置于m_outBuf下一字节的前部
m_outBuf[m_bytePos+1]|= value << (16-newBitPos);
}
//更新m_bitPos为m_outBuf当前已经填充了字节的位数,
m_bitPos= newBitPos;
//计算当前的m_bytePos值,因为本次循环至此为止,m_bytePos并没有
//改变,而m_outBuf的下一字节已经开始填充了。m_bitPos也应重新更新,
//因为m_outBuf当前字节已经填充了几位
while(m_bitPos >= 8)
{
m_bitPos-= 8;
++m_bytePos;
}
}
//缓冲区正好填充满
if(m_bytePos == m_outputBlockSize)
{
FILTER_OUTPUT(1,m_outBuf, m_outputBlockSize, 0);
m_bytePos = m_bitPos =0;//为缓冲区重新初始化作准备
}
}
//while (m_inputPosition <length)==end
//输出缓冲区的消息尾部
if (messageEnd)
{
FILTER_OUTPUT(2, m_outBuf,m_bytePos, messageEnd);
m_bytePos = m_bitPos = 0;
}
FILTER_END_NO_MESSAGE_END;
}
//CPP文件,接(2)
//BASEN解码类的初始化解码数组
//lookup为解码数组,base为字母表大小,caseInsensitive大小写是否敏感
voidBaseN_Decoder::InitializeDecodingLookupArray(int *lookup, constbyte *alphabet, unsigned int base, bool caseInsensitive)
{
std::fill(lookup, lookup+256, -1);
for (unsigned int i=0;i<base; i++)
{
if (caseInsensitive &&isalpha(alphabet[i]))
{
//忽略大小写
assert(lookup[toupper(alphabet[i])]== -1);
lookup[toupper(alphabet[i])]= i;
assert(lookup[tolower(alphabet[i])]== -1);
lookup[tolower(alphabet[i])]= i;
}
else
{
//大小写有别
assert(lookup[alphabet[i]]== -1);
lookup[alphabet[i]]= i;
}
}
}
//Grouper类独立初始化
void Grouper::IsolatedInitialize(constNameValuePairs ¶meters)
{
m_groupSize =parameters.GetIntValueWithDefault(Name::GroupSize(), 0);
ConstByteArrayParameter separator,terminator;
if (m_groupSize)
parameters.GetRequiredParameter("Grouper",Name::Separator(), separator);
else
parameters.GetValue(Name::Separator(),separator);
parameters.GetValue(Name::Terminator(),terminator);
m_separator.Assign(separator.begin(),separator.size());
m_terminator.Assign(terminator.begin(),terminator.size());
m_counter = 0;
}
//Grouper类的编码
size_t Grouper::Put2(const byte *begin, size_tlength, int messageEnd, bool blocking)
{
FILTER_BEGIN;
if (m_groupSize)
{
while (m_inputPosition <length)
{
if (m_counter== m_groupSize)
{
//组空间满,输出m_separator缓冲区
FILTER_OUTPUT(1,m_separator, m_separator.size(), 0);
m_counter= 0;
}
size_tlen;
FILTER_OUTPUT2(2,len = STDMIN(length-m_inputPosition, m_groupSize-m_counter),
begin+m_inputPosition,len, 0);
m_inputPosition+= len;
m_counter +=len;
}
}
else
//最后一个组的输出
FILTER_OUTPUT(3, begin, length,0);
if (messageEnd)
{
FILTER_OUTPUT(4, m_terminator,m_terminator.size(), messageEnd);
m_counter = 0;
}
FILTER_END_NO_MESSAGE_END
}
NAMESPACE_END
#endif
#ifndef CRYPTOPP_BASECODE_H
#define CRYPTOPP_BASECODE_H
#include "filters.h"
#include "algparam.h"
#include "argnames.h"
NAMESPACE_BEGIN(CryptoPP)
//! base n encoder, where n is a power of2
//继承关系:
//Unflushable<Filter>->BaseN_Encoder
//Unflushable<Filter>->BaseN_Decoder
//Bufferless<Filter>->Grouper
class CRYPTOPP_DLL BaseN_Encoder : publicUnflushable<Filter>
{
public:
BaseN_Encoder(BufferedTransformation*attachment=NULL)
{Detach(attachment);}
BaseN_Encoder(const byte*alphabet, int log2base, BufferedTransformation *attachment=NULL,int padding=-1)
{
Detach(attachment);
IsolatedInitialize(MakeParameters(Name::EncodingLookupArray(),alphabet)
(Name::Log2Base(),log2base)
(Name::Pad(),padding != -1)
(Name::PaddingByte(),byte(padding)));
}
voidIsolatedInitialize(const NameValuePairs ¶meters);
size_t Put2(const byte *begin, size_t length, intmessageEnd, bool blocking);
private:
const byte *m_alphabet;
int m_padding, m_bitsPerChar,m_outputBlockSize;
int m_bytePos, m_bitPos;
SecByteBlock m_outBuf;
};
//! base n decoder, where n is a power of2
class CRYPTOPP_DLL BaseN_Decoder : publicUnflushable<Filter>
{
public:
BaseN_Decoder(BufferedTransformation*attachment=NULL)
{Detach(attachment);}
BaseN_Decoder(const int*lookup, int log2base, BufferedTransformation*attachment=NULL)
{
Detach(attachment);
IsolatedInitialize(MakeParameters(Name::DecodingLookupArray(),lookup)(Name::Log2Base(), log2base));
}
voidIsolatedInitialize(const NameValuePairs ¶meters);
size_t Put2(const byte *begin, size_t length, intmessageEnd, bool blocking);
static void CRYPTOPP_APIInitializeDecodingLookupArray(int *lookup, const byte *alphabet,unsigned int base, bool caseInsensitive);
private:
const int *m_lookup;
int m_padding, m_bitsPerChar,m_outputBlockSize;
int m_bytePos, m_bitPos;
SecByteBlock m_outBuf;
};
//! filter that breaks input stream intogroups of fixed size
//将输入流分成固定大小的块
class CRYPTOPP_DLL Grouper : public Bufferless<Filter>
{
public:
Grouper(BufferedTransformation*attachment=NULL)
{Detach(attachment);}
Grouper(int groupSize, conststd::string &separator, const std::string &terminator,BufferedTransformation *attachment=NULL)
{
Detach(attachment);
IsolatedInitialize(MakeParameters(Name::GroupSize(),groupSize)
(Name::Separator(),ConstByteArrayParameter(separator))
(Name::Terminator(),ConstByteArrayParameter(terminator)));
}
voidIsolatedInitialize(const NameValuePairs ¶meters);
size_t Put2(const byte *begin, size_t length, intmessageEnd, bool blocking);
private:
SecByteBlock m_separator, m_terminator;
size_t m_groupSize, m_counter;
};
NAMESPACE_END
#endif