SecurID卡的原理实现的动态口令认证,RSA SecurID 动态密码令牌

2016年02月25日 技术资料 8193 views 0

俗称:token卡,IT男标配。使用TC采用RSA算法制作C语言代码,RSA发布iPhone版应用 - SecurID软件令牌。

163为它的游戏用户推出了动态口令卡。售价才10元。这让我非常的诧异。首先,我觉得这几乎是无懈可击的密保技术。其次,RSA的 SecurID卡在国内在几百RMB一个。而163的这东西,实在是便宜……



RSA 令牌 SID700 RSA SecurID原理

1、密码:
登陆密码=f(静态密码,动态密码)。
静态密码就是用户自己设置的一个密码。
动态密码是通过卡动态生成的密码。
f是一个简单函数。例如不进位的加法、字符串拼接。
用户的静态密码最好是不要通过电脑键盘输入不通过网络传输的,所以很不推荐采用字符串拼接的方式。


2、构成
一个8位的处理器,一个时钟,一个LCD显示屏,一块电池。可能还会有一个键盘。
外壳的设计目标:一旦打开外壳,那么立即清空内存数据。
内部的设计目标:存储一个种子文件。然后按文件中的数据和当前时间拼起来进行AES,然后hash成6-8位的数字,显示在LCD上。

如果有键盘,那么用户可以通过键盘输入一串数字(用户的静态密码)。卡把这串数字(静态密码)与卡实际生成的数字(动态密码)用一种公开的算法(前面所说的那个f)进行组合,然后显示出来。通常采用的是不进位的加法。因此这个部件不是我们所需要关心的部分。

理论上来讲,如果知道种子、如果知道时间、如果知道生成器内部所采用的算法,那么我们就可以自行的算出这个动态密码。既然RSA公司敢发布软件版的生成器,那么就意味着它不怕这个算法被知道。事实上这个算法被hacker们公开已经是10年前的事情了。一个俄国hacker在发布自己的软件模拟器后留下这样一段话:
“RSA公司的伙计们:
如果你需要人帮助你设计安全的加密算法和协议,告诉我们,我们将会帮助你做出来。俄罗斯人并不都是熊。我们的国际象棋比你们下的好,记住!”

但是难点在于从卡中取走种子文件。就目前而言,是不可能通过它产生的随机序列反推回去得到它的种子文件的。

在网上看到了另一种类似方案:
1、用户输入一个用户名,发送给服务器
2、服务器返回一个随机数,记做C
3、用户使用自己的密码unlock动态口令卡
4、用户输入C。动态口令卡计算f(C,time,seed),然后显示出来
5、用户把口令卡的结果发送给服务器6
6、用户锁住口令卡

将DKEY动态密码结合PAM认证方案,在PAM静态密码认证基础之上,增加一层宁盾动态密码(该密码是由硬件令牌产生,每隔60秒变化一次,密码一次使用有效)认证,用以提升Linux/Unix服务器安全。


原理图:

点击查看原图 SecurID卡的原理实现的动态口令认证,RSA SecurID 动态密码令牌 第1张

点击查看原图 SecurID卡的原理实现的动态口令认证,RSA SecurID 动态密码令牌 第2张


——————————————————————————————————————————

rsa编程1
要求输入p,q,e
输出d
算法描述为求逆元的方法

  1. #include <stdio.h>  

  2. #include <stdlib.h>  

  3. #include <string.h>  

  4. #include <time.h>  

  5. #include "vlong.h"  

  6. #include "rsa.h"  

  7. //生成大奇数及 e m   

  8. void MakePrime(long Level)  

  9. {  

  10.  private_key pkey;  

  11.  char prand[2][128],vername[5],tc;  

  12.  DWORD i,j,nn, nCount;  

  13.  vlong *tmp[4];  

  14.  FILE *fp;  

  15.    

  16.  srand((unsigned)time(NULL));  

  17.  if(Level == '1') //生成512位  

  18.   nCount = 32;  

  19.  else if(Level == '2') //生成1024位  

  20.   nCount = 64;  

  21.  else  //生成256位  

  22.   nCount = 16;  

  23.    

  24.  for(i=0; i<2; i++)  

  25.  {  

  26.   for(j=0; j<nCount; j++)  

  27.   {  

  28.    tc = (char)(0x41+rand()%0xAF);  

  29.    prand[i][j] = tc;  

  30.   }  

  31.   prand[i][j]=0;  

  32.  }  

  33.    

  34.  pkey.create(prand[0], prand[1]); //计算生成两个大奇数 p, q  

  35.    

  36.  tmp[0] = &pkey.p;  

  37.  tmp[1] = &pkey.q;  

  38.  tmp[2] = &pkey.e;  

  39.  tmp[3] = &pkey.m;  

  40.  strcpy(vername, "pqem");  

  41.    

  42.  fp =  fopen("RSAVar.txt", "w");  

  43.  for(j=0; j<4; j++)  

  44.  {  

  45.   nn=tmp[j]->value->n;  

  46.   fprintf(fp, "[%c]\nLen = %d\n", vername[j], nn);  

  47.   for(i=0; i<nn; i++)  

  48.   {  

  49.    fprintf(fp,"%c[%ld] = 0X%08lX;\n", vername[j],i,  tmp[j]->value->a[i]);  

  50.   }  

  51.  }  

  52.  fclose(fp);  

  53. }  

  54. //以下p,q,e,m可由 本程序的 参数 p0生成,可任意改变  

  55. #define VL 8  

  56. // p, q 仅在加密程序中用  

  57. DWORD p[VL/2]   = {0Xb2ab9d39, 0X8e53d98d, 0X77dd8ec1,0X995283d6};  

  58. DWORD q[VL/2]   = {0Xc7e37a29, 0X7fb7c168, 0Xea61d2a3,0Xcaab6cd8};  

  59. // e, m 在加解密程序中都要  

  60. DWORD e       =  0X00010001;  

  61. DWORD m[VL] = {0X1ef45821,0X71a30c63,0Xe3a16b86,0Xce0e1e51  

  62.      ,0X462d92c1,0X4ac42393,0X04749e17,0X7961c756};  

  63. //加密  

  64. void Encrypt()  

  65. {  

  66.  // 准备p.q.m.e  

  67.  private_key pkey;    //私匙类,数据保密  

  68.  pkey.p.load(p,VL/2);  

  69.  pkey.q.load(q,VL/2);  

  70.  pkey.e = e;  

  71.  pkey.m.load(m, VL);  

  72.    

  73.  DWORD a[VL];  

  74.  //准备要加密的数,这里,只对两个DWORD值加密,卡号和计算机标识符  

  75.  //读入卡号和标识符框中的当前值  

  76.  memset(a,0,VL*sizeof(DWORD));  

  77.  printf("Please Input CardNo & PCID (Fmt %%X-%%X):\n");  

  78.  scanf("%lX-%lX",&a[0], &a[1]);  

  79.  vlong m;   

  80.  m.load(a, 2); //这样 m 中就保存有要加密的数  

  81.    

  82.  //计算加密后的数c  

  83.  vlong c = pkey.decrypt(m);  

  84.  c.store(a, VL);  

  85. //以下只是对 VL == 8的情况的处理  

  86.  //由于pkey中的成员m,是一小于8个DWORD值的数,加密后的 c < pkey.m  

  87.  //所以,a[7]的高位总为0, 以防a[6],a[7]过多的高位为0,对a[7]变换处理一下  

  88.  a[7] ^= (a[1]+a[2]+a[3]+a[4]);  

  89.  a[6] ^= (a[0]+a[5]);  

  90.  //加密后的结果就是 a[0]-a[7]  

  91.  FILE *fp =  fopen("nwnb.txt", "w");  

  92.  if(fp != NULL)  

  93.  {  

  94.  fprintf(fp,"%08lX-%08lX-%08lX-%08lX-%08lX-%08lX-%08lX-%08lX\n",   

  95.   a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);  

  96.  fclose(fp);  

  97.  }  

  98.  printf("Encrypt Data:\n");  

  99.  printf("%08lX-%08lX-%08lX-%08lX-%08lX-%08lX-%08lX-%08lX\n",   

  100.   a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);  

  101. }  

  102. void Decrypt()  

  103. {  

  104.  //准备 [m] [e], 解密只用到 m,e  

  105.  public_key pkey;     //公匙类,数据公开  

  106.  pkey.e = e;  

  107.  pkey.m.load(m, VL);  

  108.  DWORD a[VL];  

  109.    

  110.  //读入加密后的VL个DWORD值到a可  

  111.  memset(a,0,VL*sizeof(long));  

  112.  FILE *fp =  fopen("nwnb.txt", "r");  

  113.  if(fp != NULL)  

  114.  {  

  115.  fscanf(fp,"%08lX-%08lX-%08lX-%08lX-%08lX-%08lX-%08lX-%08lX\n",   

  116.   &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6], &a[7]);  

  117.  fclose(fp);  

  118.  }  

  119.  //还原a[6],a[7]  

  120.  a[7] ^= (a[1]+a[2]+a[3]+a[4]);  

  121.  a[6] ^= (a[0]+a[5]);  

  122.  //加密的数据保存到m中  

  123.  vlong m;  

  124.  m.load(a,8);  

  125.    

  126.  //计算加密前的数据,保存在c中  

  127.  vlong c = pkey.encrypt(m);  

  128.  memset(a,0,8*sizeof(long));  

  129.  c.store(a,2);   

  130.  // a[0], a[1]就是加密前的数据  

  131.  printf("Decrypt Data:\n");  

  132.  printf("%08lX-%08lX\n", a[0], a[1]);  

  133. }  

  134. void Help()  

  135. {  

  136. printf("欢迎访问贝壳iT -- https://itcat.cn/ \n");  

  137.  printf("By: Seraph Chutium  2001.7.21 \n");  

  138.  printf("Usage:  Work  P0                  准备256位的加解密\n");  

  139.  printf("Usage:  Work  P1                  准备512位的加解密\n");  

  140.  printf("Usage:  Work  P2                  准备1024位的加解密\n");  

  141.  printf("Usage:  Work  E                   加密\n");  

  142.  printf("Usage:  Work  D                   解密\n");  

  143. }  

  144. void main(int nArg, char **sArg)  

  145. {  

  146.  if(nArg < 2)  

  147.  {  

  148.   Help();  

  149.   return;  

  150.  }  

  151.    

  152.  if(sArg[1][0] == 'P' || sArg[1][0] == 'p')  

  153.  {  

  154.   MakePrime(sArg[1][1]);  

  155.   return;  

  156.  }  

  157.  else if(sArg[1][0] == 'E' || sArg[1][0] == 'e')  

  158.   Encrypt();  

  159.  else if(sArg[1][0] == 'D' || sArg[1][0] == 'd')  

  160.   Decrypt();  

  161.  else  

  162.   Help();  

  163. }  

👍好活当赏🧧