SM2算法和RSA算法简介

  SM2算法和RSA算法都是公钥密码算法,SM2算法是一种更先进安全的算法,在安全性能、速度性能等方面都优于RSA算法,在我国商用密码体系中被用来替换RSA算法。国家密码管理局于2010年12月17日发布了SM2算法,并要求现有的基于RSA算法的电子认证系统、密钥管理系统、应用系统进升级改造,使用SM2算法。
  
  SM2算法和RSA算法简介
  
  RSA公钥加密算法是美国计算机学家Ron Rivest、Adi Shamir和Leonard Adleman于1977年提出,是最早的公钥加密算法之一,在全球范围被广泛使用。随着密码技术和计算机技术的发展,目前1024位RSA算法已经被证实存在被攻击的风险,美国NIST(国家标准技术研究院)在2010年要求全面禁用1024位RSA算法,升级到2048位RSA算法。此外,斯诺登事件爆发后,其泄露出的机密文档显示,RSA算法中可能存在NSA的预置后门,对RSA算法的安全性产生巨大影响。
  
  SM2算法由国家密码管理局于2010年12月17日发布,是我国自主设计的公钥密码算法,基于更加安全先进的椭圆曲线密码机制,在国际标准的ECC椭圆曲线密码理论基础上进行自主研发设计,具备ECC算法的性能特点并实现优化改进。
  
  SM2算法和RSA算法性能对比
  
  SM2算法和RSA算法都属于公钥加密算法,但两者分别基于不同的数学理论基础。与RSA算法相比,SM2算法具有抗攻击性强、CPU 占用少、内容使用少、网络消耗低、加密速度快等特点。
  
  (1)SM2算法与RSA算法安全性能对比
  
  RSA算法是基于大整数因子分解数学难题(IFP)设计的,其数学原理相对简单,在工程应用中比较易于实现,但它的单位安全强度相对较低。对大整数做因子分解的难度决定了RSA算法的可靠性,随着计算机运算速度的提高和分布式计算的发展,加上因子分解方法的改进,对低位数的密钥攻击已成为可能。
  
  ECC(EllipticCurves Cryptography,椭圆曲线密码编码学)是由Koblitz和Miller两人于1985年提出,其数学基础是基于椭圆曲线上离散对数计算难题(ECDLP)。ECC算法的数学理论非常深奥和复杂,在工程应用中比较难以实现,但它的单位安全强度相对较高。用国际上公认的针对ECC算法最有效的攻击方法——Pollard rho方法去破译和攻击ECC算法,它的破译或求解难度基本上是指数级的。
  
  因此,ECC算法的单位安全强度远高于RSA算法,可以用较少的计算能力提供比RSA算法更高的安全强度,而所需的密钥长度却远比RSA算法低。目前,基于ECC的SM2证书普遍采用256位密钥长度,加密强度等同于3072位RSA证书,远高于业界普遍采用的2048位RSA证书。
  
  此外,为了提高安全强度必须不断增加密钥长度,ECC算法密钥长度增长速度较慢(例如:224-256-384),而RSA算法密钥长度则需呈倍数增长(例如:1024-2048-4096)。
  
  (2)SM2算法与RSA算法速度性能对比
  
  在TLS握手过程中,更长的密钥意味着必须来回发送更多的数据以验证连接,产生更大的性能损耗和时间延迟。因此,ECC算法能够以较小的密钥和较少的数据传递建立HTTPS连接,在确保相同安全强度的前提下提升连接速度。经国外有关权威机构测试,在Apache和IIS服务器采用ECC算法,Web服务器响应时间比RSA算法快十几倍。
  
  SM2算法的优化和先进性
  
  SM2算法是我国基于ECC椭圆曲线密码理论自主研发设计,由国家密码管理局于2010年12月17日发布,在密码行业标准GMT 0003.1-2012 SM2 总则中推荐了一条256位曲线作为标准曲线,数字签名算法、密钥交换协议以及公钥加密算法都根据SM2总则选取的有限域和椭圆曲线生成密钥对;在数字签名、密钥交换方面区别于ECDSA、ECDH等国际算法,而是采取了更为安全的机制,提高了计算量和复杂性;在数字签名和验证、消息认证码的生成与验证以及随机数的生成等方面,使用国家密管理局批准的SM3密码杂凑算法和随机数生成器。SM3杂凑算法是我国自主设计的密码杂凑算法,安全性要高于MD5算法(128位)和SHA-1算法(160位),SM3算法的压缩函数与SHA-256具有相似结构,但设计更加复杂;SM4分组密码算法是我国自主设计的分组对称密码算法,与AES算法具有相同的密钥长度128位,在安全性上高于3DES算法,在实际应用中能够抵抗针对分组密码算法的各种攻击方法。
  
  SM2算法的应用推广
  
  密码算法的安全性是信息安全保障的核心,通过自主可控的国产密码技术保护重要数据的安全,是有效提升我国信息安全保障水平的重要举措。我国大力推动SM2国产密码算法替换目前所采用的RSA算法,一方面规避RSA算法存在的脆弱性和“预置后门”等安全风险,另一方面确保密码算法这一关键环节的自主可控,保障我国信息安全基础设施的安全可信。中办2018年36号文件《金融和重要领域密码应用与创新发展工作规划(2018-2022年)》以及相关法规文件均要求我国金融和重要领域密码应用采用SM2国产密码算法体系。
  
  然而,由于国密算法尚未实现广泛兼容,在主流浏览器、操作系统等终端环境中不受信任,面向互联网的产品应用中采用国产密码算法将无法满足可用性、易用性和全球通用性的需求,在实际应用中很难真正落地实施。
  
  const response = {
  
  settings: {
  
  nullValue: null,
  
  height: 400,
  
  animationDuration: 0,
  
  headerText: '',
  
  showSplashScreen: false
  
  }
  
  };
  
  const undefinedValue = response.settings?.undefinedValue ?? 'some other default'; // result: 'some other default'
  
  const nullValue = response.settings?.nullValue ?? 'some other default'; // result: 'some other default'
  
  const headerText = response.settings?.headerText ?? 'Hello, world!'; // result: ''
  
  const animationDuration = response.settings?.animationDuration ?? 300; // result: 0
  
  const showSplashScreen = response.settings?.showSplashScreen ?? true; // result: false
  
  0 || 1 的结果是 1,因为 0 判定为 false,而 || 在前面的变量为 false 型才继续执行,而我们想要的是 “前面的对象不存在时才使用后面的值”。?? 则代表了 “前面的对象不存在” 这个含义,即便值为 0 也会认为这个值是存在的。
  
  Optional chaining 也可以用在方法上:
  
  iterator.return?.()
  
  或者试图调用某些未被实现的方法:
  
  if (myForm.checkValidity?.() === false) { // skip the test in older web browsers
  
  // form validation fails
  
  return;
  
  }
  
  比如某个旧版本浏览器不支持 myForm.checkValidity 方法,则不会报错,而是返回 false。
  
  已有实现调研
  
  Optional chaining 在 C#、Swift、CoffeeScript、Kotlin、Dart、Ruby、Groovy 已经实现了,且实现方式均有差异,可以看到每个语言在实现语法时都是有取舍的,但是大方向基本是相同的。
  
  想了解其他语言是如何实现 Optional chaining 的读者可以 点击阅读原文。
  
  这些语言实现 Optional chaining 的差异基本在 语法、支持范围、边界情况处理 等不同,所以如果你每天要在不同语言之间切换工作,看似相同的语法,但不同的细节可能把你绕晕(所以会的语言多,只会让你变成一个速记字典,满脑子都是哪些语言在哪些语法讨论倾向哪一边,选择了哪些特性这些毫无意义的结论,如果不想记这些,基础语法都没有掌握怎么好意思说会这门语言呢?所以学 JS 就够了)。
  
  语法
  
  Optional Chaining 的语法有三种使用场景:
  
  obj?.prop // optional static property access
  
  obj?.[expr] // optional dynamic property access
  
  func?.(...args) // optional function or method call
  
  也就是将 . 替换为 .?,但要注意第二行与第三行稍稍有点反直觉,比如在函数调用时,需要将 func(...args) 写为 func?.(...args)。至于为什么语法不是 func?(...args) 这种简洁一点的表达方式,在 FAQ 中有提到这个例子:
  
  obj?[expr].filter(fun):0 引擎难以判断 obj?[expr] 是 Optional Chaning,亦或这是一个普通的三元运算语句。
  
  可见,要支持 .? 这个看似简单的语法,在整个 JS 语法体系中要考虑的边界情况很多。
  
  即便是 .? 这样完整的用法,也需要注意 foo?.3:0 这种情况,不能将 foo?. 解析为 Optional chanining,而要将其解析为 foo? .3 : 0,这需要解析引擎支持 lookahead 特性。
  
  语义
  
  当 .? 前面的变量值为 null 或 undefined 时,.? 返回的结果为 undefined。
  
  a?.b // undefined if `a` is null/undefined, `a.b` otherwise.
  
  a == null ? undefined : a.b
  
  a?.[x] // undefined if `a` is null/undefined, `a[x]` otherwise.
  
  a == null ? undefined : a[x]
  
  a?.b() // undefined if `a` is null/undefined
  
  a == null ? undefined : a.b(www.chenhaopt.cn) // throws a TypeError if `a.b` is not a function
  
  // otherwise, evaluates to `a.b()`
  
  a?.() // undefined if `a` is null/undefined
  
  a == null ? undefined : a(www.yifayuLed.cn) // throws a TypeError if `a` is neither null/undefined, nor a function
  
  // invokes the function `a` otherwise
  
  短路
  
  所谓短路,就是指引入了 Optional chaining 后,某些看似一定会执行的语句在特定情况下会短路(终止执行),比如:
  
  a?.[++x] // `x` is incremented if and only if `www.sengshiyuLe.cn` is not null/undefined
  
  a == null ? undefined : a[++x]
  
  第一个例子,如果 a 时 null/undefined,就不会执行 ++x。
  
  原因是这段代码部分等价于 a == null ? undefined : a[++x],如果 a == null 为真,自然不会执行 a[++x] 这个语句。但由于 Optional chaining 使这个语句变得 “简洁了”,虽然带来了便利,但也可能导致看不清完整的执行逻辑,引发误判。
  
  所以看到 ?. 语句时,一定要反射性的思考一下,这个语句会触发 “短路”。
  
  长“短路”
  
  Optional chaining 在 JS 的规范中,作用域仅限于调用处。看下面的例子:
  
  a?.b.c(++x).d // if `a` is null/undefined, evaluates to undefined. Variable `x` is not incremented.
  
  // otherwise, evaluates to `a.b.c(++x).d`.
  
  a == null ? undefined : a.b.c(++x).d
  
  可以看到 ?. 仅在 a?. 这一层生效,而不是对后续的 b.c、c(++x).d 继续生效。而对于 C+ 与 CoffeeScript,这个语法是对后续所有 get 生效的(这里再次提醒,不要用 CoffeeScript 了,因为对于相同语法,语义都发生了变化,对你与你的同事都是巨大的理解负担,或者说没有人愿意注意,为什么代码在 CoffeeScript 里不报错,而转移到 JS 就报错了,是因为 Optional chaining 语义不一致造成的。)。
  
  正因为 Optional chaining 在 JS 语法中仅对当前位置起保护作用,因此一个调用语句中允许出现多个 .? 调用:
  
  a?.b[3].c?.(x).d
  
  a == null ? undefined : a.b[www.csyLdL.com].c == null ? undefined : a.b[3].c(x).d
  
  // (as always, except that `a` and `a.b[3].c` are evaluated only once)
  
  上面这段代码,对 a.?b、c?.(www.chaoyuL.com) 的访问与调用是安全的,而对于 b[3]、 b[3].c、c?.(x).d 的调用是不安全的。
  
  在 FAQ 环节也提到了,为什么不学习 C# 与 CoffeeScript 的语义,将安全保护从 a?. 之后就一路 “贯穿” 下去?
  
  原因是 JS 对 Optional chaining 的理解不同导致的。Optional chaining 仅仅是安全访问保护,不代表 try catch,也就是它不会捕获异常,举一个例子:
  
  a?.b()
  
  这个调用,在 a.b 不是一个函数时依然会报错,原因就是 Optional chaining 仅提供了对属性访问的安全保护,不代表对整个执行过程进行安全保护,该抛出异常还是会抛出异常,因此 Optional chaining 没有必要对后面的属性访问安全性负责。
  
  笔者认为 TC39 对这个属性的理解是合理的,否则用 try catch 就能代替 Optional chaining 了。让一个特性仅实现分内的功能,是每个前端从业者都要具备的思维能力。
  
  PS:笔者再多提一句,在任何技术设计领域,这个概念都适用。想想你设计的功能,写过的函数,如果为了图方便,扩大了其功能,终究会带来整体设计的混乱,适得其反。
  
  边界情况 - 分组
  
  我们知道,JS 代码可以通过括号的方式进行分组,分组内的代码拥有更高的执行优先级。那么在 Optional chaining 场景下考虑这个情况:
  
  (a?.b).c
  
  (a == null ? undefined : a.b).c
  
  与不带括号的进行对比:
  
  a?.b.c
  
  a == null ? undefined : a.b.c
  
  我们会发现,由于括号提高了优先级,导致在 a 为 null/undefined 时,解析出了 undefined.c 这个必定报错的荒谬语法。因此我们不要试图为 Optional chaining 进行括号分组,这样会打破逻辑顺序,使安全保护不但不生效,反而导致报错。
  
  Optional delete

转载于:https://www.cnblogs.com/qwangxiao/p/11038238.html

你可能感兴趣的:(SM2算法和RSA算法简介)