Nisy 发表于 2019-5-25 14:29:46

LibTomMath 库大数赋值、内存存储、及数据转换

我们在做RSA的时候,一定会遇到数据存储问题。
比如OpenSSL中的大数存储,我们可以通过字符串赋值,但在内存中看到大数的数据时,发现数据是反向存储的。

例如,我们将字符串 “1234567890ABCDEF” 赋值为一个大数,

而大数在内存中的格式为:0x00492750 EF CD AB 90 78 56 34 12

这个就是数据的大尾和小尾区别。

好比我们写是数字:一万两千三百四十五 12345 ,高位在左侧,低位在右端,我们称之为大尾模式,或大端模式,

对于内存中,我们平时看到的 DWORD 数据 0x12345678, 在内存中存储顺序为:78 56 34 12 , 将高位存储在右端高地址,这种叫小端(小尾)模式。

OpenSSL中大数的存储也是小端(小尾)模式,高位再高地址,所以我们在内存中看到的此类的大数HEX数据,提取出来后,需要将ASCII字符串先倒序后(转换为大端模式),再将其赋值BIG_NUM,才可以正确运算。

下面说一下 TomMath 库中大数的格式及内存形式,一下为库的一些数据转换函数,看起来很复杂的样子:


int mp_unsigned_bin_size(const mp_int *a);
int mp_read_unsigned_bin(mp_int *a, const unsigned char *b, int c);
int mp_to_unsigned_bin(const mp_int *a, unsigned char *b);
int mp_to_unsigned_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen);

int mp_signed_bin_size(const mp_int *a);
int mp_read_signed_bin(mp_int *a, const unsigned char *b, int c);
int mp_to_signed_bin(const mp_int *a,unsigned char *b);
int mp_to_signed_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen);

int mp_read_radix(mp_int *a, const char *str, int radix);      // 高位-->低位小尾字符序列 <内存中为大尾模式>
int mp_toradix(const mp_int *a, char *str, int radix);      // 转为 小尾序列
int mp_toradix_n(const mp_int *a, char *str, int radix, int maxlen);
int mp_radix_size(const mp_int *a, int radix, int *size);



mp_read_radix 从ASCII读取大数,同Openssl,我们写个代码来分析一下(库源码也是开源的,有兴趣可以读一下):


      char sn[] = "BB7F51983FD8707FD6227C23DEF5D5377A5A737CEF3C5252E578EFE136DF87B50473F9341F1640C8D258034E14C16993FCE6C6B8C3CEEB65FC8FBCD8EB77B3B05AC7C4D09E0FA1BA2EFE87D3184DB6718AE41A7CAD89B8DCE0FE80CEB523D5D647F9DB58A31D2E71AC677E67FA6E75820736C9893761EE4ACD11F31DBDC349EF";

      char szBuffer0 = {0};
      unsigned char szBuffer1 = {0};
      unsigned char szBuffer2 = {0};


      mp_intcc;
      mp_init(&cc);
      int nn = 0;
      
      nn = mp_read_radix( &cc, sn, 0x10 );    // 从ASCII字符串初始化大数ASCII数据为大端(大尾)模式
      
      nn = mp_toradix( &cc, szBuffer0, 0x10 );    // 将大数转为 ASCII 字符串(大尾模式)

      nn =mp_to_signed_bin( &cc, szBuffer1 );// 将大数转换为带符号的 BIN(hex)数据( HEX数据为大尾模式)

      nn =mp_to_unsigned_bin( &cc, szBuffer2 ); // ( HEX数据为大尾模式)





// mp_read_radix 字符串变为大数后的模型,TomMath 是以 DWORD (0xFFF-FFFF)为单元来作为基本单元的,其他的大数则是以字节 0xFF 作为技术单元。
// 这个你如果自己写过大数库就自然了解这些区别了,不多解释,所以我们如果直接提取 TomMath 的内存数据是不可以直接使用的,但是转换起来也比较简单:
hex:


LibTomMath 库中 RSA 的算法实现也比较简单,先用 RSA-tools 构造一组1024的 N、D、e,再随意找一段小于1024为的数据作为M,计算结束后将大数 mp_toradix 转换为 ASCII,即可得到我们输入的ASCII 字符串 M,ASCII顺序即为高位-->低位。


void TestC()
{
      char * szN = "98AE442902D70AC203229CB2586C2AB36CE31B01FB428AADC7CD2C3DF8F4508E930ED6603C4145B10EEA5996C3473FD131EB20780F2FE4F4239B988E04626D5E9C2C4FE71F5135F903250C161C978C120C3E9D9E7F6A2F75F38F74C501352EACC028CCEE15BE04ED34980CE3915B2957218A474D982C77261C8B6E4AB85920C9";
      char * szD = "19B93F6C32A7E7664E1850A1D2A4719C7A492CD764F15D4D83BB747BEB985731A00E25D0317662FCD60ED5FFB6D3C2B35511207B190DC4A81C6F87FB85A68C7D814A7086C221586B14F4BDA7F55D5C59DC32E903480D5616D3F5BA7398762B5ACD6468E56CD7402E1F87FB88A764F3727C7EEB49FB80CE7DFC930E335F2FEA83";
      char * szE = "10003";
      char * szM = "20E832BD15F3651FB298E54CE623DF8DFA5323827650098A1353558A43D5D7BB644466DBFA2F65E81F79CD9BBAF419DB0A3F0A1AC4B18F95848759F6CE4E23899AB148A953FBB857CA20BA732EE5432353DD063F187D9A55565E048C97705DF0305DC8AEEBC613494C2BE857971F1FB5C82A7BDB90891B2814FFEBDBFC";
      char szC = {0};

      mp_int n;
      mp_int e;
      mp_int d;
      mp_int m;
      mp_int c;
      mp_int mm;

      mp_init(&n);
      mp_init(&e);
      mp_init(&d);
      mp_init(&m);
      mp_init(&c);
      mp_init(&mm);

      int nn = 0;

      nn = mp_read_radix( &n, szN, 0x10 );
      nn = mp_read_radix( &d, szD, 0x10 );
      nn = mp_read_radix( &e, szE, 0x10 );
      nn = mp_read_radix( &m, szM, 0x10 );

      // c = m^e (mod n)
      mp_exptmod( &m, &e, &n, &c );

      // m = c^d (mod n)
      mp_exptmod( &c, &d, &n, &mm );

      char szBuffer;
      nn = mp_toradix(&mm, szBuffer, 0x10);

      // Hex ==> BigNum int 为单位
      // 内存模式为 max: 0xFFF-FFFF
      // mp_toradix 即可将大数转换为 ASCII(大端(大尾)模式)即我们初始化大数的字符串

      return ;

}

不破不立 发表于 2019-5-25 16:41:50

收藏,学习,谢谢校长

id9522 发表于 2019-5-27 15:22:31

学习了,谢谢校长。

sangel 发表于 2019-5-30 01:25:46

学习了,多谢分享。

tiger2003 发表于 2019-6-9 12:06:29

非常不错,非常感谢!
页: [1]
查看完整版本: LibTomMath 库大数赋值、内存存储、及数据转换