飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 4373|回复: 4

[C/C++] LibTomMath 库大数赋值、内存存储、及数据转换

[复制链接]

该用户从未签到

发表于 2019-5-25 14:29:46 | 显示全部楼层 |阅读模式
我们在做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 库中大数的格式及内存形式,一下为库的一些数据转换函数,看起来很复杂的样子:


  1. int mp_unsigned_bin_size(const mp_int *a);
  2. int mp_read_unsigned_bin(mp_int *a, const unsigned char *b, int c);
  3. int mp_to_unsigned_bin(const mp_int *a, unsigned char *b);
  4. int mp_to_unsigned_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen);

  5. int mp_signed_bin_size(const mp_int *a);
  6. int mp_read_signed_bin(mp_int *a, const unsigned char *b, int c);
  7. int mp_to_signed_bin(const mp_int *a,  unsigned char *b);
  8. int mp_to_signed_bin_n(const mp_int *a, unsigned char *b, unsigned long *outlen);

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

复制代码


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


  1.         char sn[] = "BB7F51983FD8707FD6227C23DEF5D5377A5A737CEF3C5252E578EFE136DF87B50473F9341F1640C8D258034E14C16993FCE6C6B8C3CEEB65FC8FBCD8EB77B3B05AC7C4D09E0FA1BA2EFE87D3184DB6718AE41A7CAD89B8DCE0FE80CEB523D5D647F9DB58A31D2E71AC677E67FA6E75820736C9893761EE4ACD11F31DBDC349EF";

  2.         char szBuffer0[0x200] = {0};
  3.         unsigned char szBuffer1[0x200] = {0};
  4.         unsigned char szBuffer2[0x200] = {0};


  5.         mp_int  cc;
  6.         mp_init(&cc);
  7.         int nn = 0;
  8.         
  9.         nn = mp_read_radix( &cc, sn, 0x10 );    // 从ASCII字符串初始化大数  ASCII数据为大端(大尾)模式
  10.         
  11.         nn = mp_toradix( &cc, szBuffer0, 0x10 );    // 将大数转为 ASCII 字符串(大尾模式)

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

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

复制代码



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



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


  1. void TestC()
  2. {
  3.         char * szN = "98AE442902D70AC203229CB2586C2AB36CE31B01FB428AADC7CD2C3DF8F4508E930ED6603C4145B10EEA5996C3473FD131EB20780F2FE4F4239B988E04626D5E9C2C4FE71F5135F903250C161C978C120C3E9D9E7F6A2F75F38F74C501352EACC028CCEE15BE04ED34980CE3915B2957218A474D982C77261C8B6E4AB85920C9";
  4.         char * szD = "19B93F6C32A7E7664E1850A1D2A4719C7A492CD764F15D4D83BB747BEB985731A00E25D0317662FCD60ED5FFB6D3C2B35511207B190DC4A81C6F87FB85A68C7D814A7086C221586B14F4BDA7F55D5C59DC32E903480D5616D3F5BA7398762B5ACD6468E56CD7402E1F87FB88A764F3727C7EEB49FB80CE7DFC930E335F2FEA83";
  5.         char * szE = "10003";
  6.         char * szM = "20E832BD15F3651FB298E54CE623DF8DFA5323827650098A1353558A43D5D7BB644466DBFA2F65E81F79CD9BBAF419DB0A3F0A1AC4B18F95848759F6CE4E23899AB148A953FBB857CA20BA732EE5432353DD063F187D9A55565E048C97705DF0305DC8AEEBC613494C2BE857971F1FB5C82A7BDB90891B2814FFEBDBFC";
  7.         char szC[0x200] = {0};

  8.         mp_int n;
  9.         mp_int e;
  10.         mp_int d;
  11.         mp_int m;
  12.         mp_int c;
  13.         mp_int mm;

  14.         mp_init(&n);
  15.         mp_init(&e);
  16.         mp_init(&d);
  17.         mp_init(&m);
  18.         mp_init(&c);
  19.         mp_init(&mm);

  20.         int nn = 0;

  21.         nn = mp_read_radix( &n, szN, 0x10 );
  22.         nn = mp_read_radix( &d, szD, 0x10 );
  23.         nn = mp_read_radix( &e, szE, 0x10 );
  24.         nn = mp_read_radix( &m, szM, 0x10 );

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

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

  29.         char szBuffer[0x200];
  30.         nn = mp_toradix(&mm, szBuffer, 0x10);

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

  34.         return ;

  35. }
复制代码

评分

参与人数 1威望 +1 飘云币 +1 收起 理由
九层楼 + 1 + 1 吃水不忘打井人,给个评分懂感恩!

查看全部评分

PYG19周年生日快乐!
  • TA的每日心情
    开心
    12 小时前
  • 签到天数: 2178 天

    [LV.Master]伴坛终老

    发表于 2019-5-25 16:41:50 | 显示全部楼层
    收藏,学习,谢谢校长
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2019-11-16 22:51
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2019-5-27 15:22:31 | 显示全部楼层
    学习了,谢谢校长。
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    昨天 10:40
  • 签到天数: 766 天

    [LV.10]以坛为家III

    发表于 2019-5-30 01:25:46 | 显示全部楼层
    学习了,多谢分享。
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2019-6-9 11:43
  • 签到天数: 5 天

    [LV.2]偶尔看看I

    发表于 2019-6-9 12:06:29 | 显示全部楼层
    非常不错,非常感谢!
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表