异或加密(XOR)原理及实现 (**)

目录

XOR 加密简介

异或加密算法(包含一个简单的 C语言 加解密源码

异或加密(XOR)原理及实现

=======================================

异或加密(XOR)原理及实现

用 js 实现了一个 在线 加密解密的小工具,支持中文作为密钥,欢迎尝试啦

https://www.boydwang.com/xor.html

什么是异或加密

异或加密是一种加密算法,利用了计算机中的异或计算,异或计算(符号记为 ‘^’)的原理是,相同为 0,不同为 1

0 ^ 0 = 0
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1

由于 1 ^ 0 或 0 ^ 1 的结果都为 1,因此,不能直接由结果 1 推出原来的明文到底是 0 还是 1,达到保护明文的目的。

异或加密特性

异或加密具有以下特性(引自维基百科):

简单异或密码(英语:simple XOR cipher)是密码学中一种简单的加密算法,它按照如下原则进行运算:
1. A ^ 0 = A
2. A ^ A = 0
3. (A ^ B) ^ C = A ^ (B ^ C) 
4. (B ^ A) ^ A = B ^ 0 = B   // 明文 B;密码 A

从原理 4 可得,对同一个明文 B,使用密钥 A 对其进行两次异或运算,可得到明文 B,我们正是利用了这一特性,进行实现加密解密

异或加密算法

异或加密算法由 3 部分组成,分别是

  1. 明文
  2. 密钥
  3. 异或运算规则

流程是通过遍历明文的每一个字符,并按照异或运算规则从密钥中取出一个或多个字符,与明文的字符进行异或运算,将异或的结果合成一个新的字符串,

但是由于异或运算的特性,有可能异或运算后为一个不可见字符,就可能无法通过字符串传递密文了,因此这里引入了 base64 编码,因为 base64 编码后的字符串都是可见字符

关于 base64 编码的知识详见 Js Base64 编码 

所以加密算法变成:

  1. 明文与密钥按照异或运算规则进行异或运算,产生密钥
  2. 将得到的密文进行base64 编码,最后返回

而解密算法相应的变成:

  1. 将密文进行 base64 解码,得到原始的密文
  2. 将密文按照相同的异或运算规则与密文进行异或,得到明文

异或运算算法

异或运算算法是为了解决明文与密文如何进行异或运算的问题,因为明文和密文长度可能不一样,如何保证明文的每个字符都有与之对应的密文字符进行异或,并且在解密时保证按照相同的算法进行异或运算得到明文,是异或运算算法要考虑的,这里我们会用到一种新的运算,叫 取余,这里不考虑为负数的情况

取余运算(通常记为 %),表示的是 被除数 除以 除数之后的余数,比如 8 / 5 = 1 余 3,因此 8 % 5 = 3,另外取余运算规定如果被除数小于除数,那么取余结果就为被除数,因此 5 % 8 = 5,来看下面的例子:

0%3=0 
1%3=1
2%3=2
3%3=0
4%3=1
5%3=2
6%3=0
7%3=1

你们发现了吗,结果总是 0,1,2 的循环,我们就可以通过让明文每个字符的索引对密文的总长度取余,得到的结果作为密文的索引下标,取出对应的密文字符,与明文字符进行异或运算就可以啦

看下面这个例子吧

Power shell 实现

可以通过改变变量 key 的值更换加密密钥

$Script:key = "3567d8cndkei%*x9(-32[]KDF(32222"

function Decode($cyphertext) {
    $keyArray =[System.Text.Encoding]::ASCII.GetBytes($key)
    $encodedArray= [System.Text.Encoding]::ASCII.GetBytes([System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($cyphertext)))
    $plainText = ""
    $keyposition = 0
    $encodedArray | foreach-object -process {
        $plainText += [char]($_ -bxor $KeyArray[$keyposition % $KeyArray.Length])
        $keyposition += 1
    }

    return $plainText
}

function Encode($plainText)
{
    $KeyArray= [System.Text.Encoding]::ASCII.GetBytes($key)
    $cyphertext = [System.Byte[]]::new($plainText.Length);
    $keyposition = 0
    $plainText.ToCharArray() | foreach-object -process {
        $cyphertext[$keyposition] = $_ -bxor $KeyArray[$keyposition % $KeyArray.Length]
        $keyposition += 1
    }

    return [Convert]::ToBase64String($cyphertext)
}

测试

Decode(Encode("324328***)x-sdfsaf2344")) | out-string

结果

与未加密的数据结果一样

image

https://www.boydwang.com/2019/01/xor-powershell/

=======================================

XOR 加密简介

作者: 阮一峰

日期: 2017年5月31日

本文介绍一种简单高效、非常安全的加密方法:XOR 加密。

一、 XOR 运算

逻辑运算之中,除了 AND 和 OR,还有一种 XOR 运算,中文称为"异或运算"。

它的定义是:两个值相同时,返回false,否则返回true。也就是说,XOR可以用来判断两个值是否不同。

        true XOR true // false
        false XOR false // false
        true XOR false // true
        true XOR false // true

JavaScript 语言的二进制运算,有一个专门的 XOR 运算符,写作^。
        1 ^ 1 // 0
        0 ^ 0 // 0
        1 ^ 0 // 1
        0 ^ 1 // 1

上面代码中,如果两个二进制位相同,就返回0,表示false;否则返回1,表示true。

二、 XOR 的应用

XOR 运算有一个很奇妙的特点:如果对一个值连续做两次 XOR,会返回这个值本身。

        // 第一次 XOR
        1010 ^ 1111 // 0101
         
        // 第二次 XOR
        0101 ^ 1111 // 1010

上面代码中,原始值是1010,再任意选择一个值(上例是1111),做两次 XOR,最后总是会得到原始值1010。这在数学上是很容易证明的。


三、加密应用

XOR 的这个特点,使得它可以用于信息的加密。        

        message XOR key // cipherText
        cipherText XOR key // message

上面代码中,原始信息是message,密钥是key,第一次 XOR 会得到加密文本cipherText。对方拿到以后,再用key做一次 XOR 运算,就会还原得到message。

四、完美保密性

二战期间,各国为了电报加密,对密码学进行了大量的研究和实践,其中就包括 XOR 加密。

战后,美国数学家香农(Claude Shannon)将他的研究成果公开发表,证明了只要满足两个条件,XOR 加密是无法破解的。

key的长度大于等于message  //即:同一份加密后的密文,不会出现分段的重复。除非刻意,否则,太长的 key,实用吗?所以重复难免?

 
key必须是一次性的,且每次都要随机产生 //即:多份加密后的不同密文之间,也不会出现重复

理由很简单,如果每次的key都是随机的,那么产生的CipherText具有所有可能的值,而且是均匀分布,无法从CipherText看出message的任何特征。也就是说,它具有最大的"信息熵",因此完全不可能破解。这被称为 XOR 的"完美保密性"(perfect secrecy)。

满足上面两个条件的key,叫做 one-time pad(缩写为OTP),意思是"一次性密码本",因为以前这样的key都是印刷成密码本,每次使用的时候,必须从其中挑选key。

五、实例:哈希加密

下面的例子使用 XOR,对用户的登陆密码进行加密。实际运行效果看这里。

第一步,用户设置登陆密码的时候,算出这个密码的哈希,这里使用的是 MD5 算法,也可以采用其他哈希算法。

        const message = md5(password);

第二步,生成一个随机的 key。

        // 生成一个随机整数,范围是 [min, max]
        function getRandomInt(min, max) {
          return Math.floor(Math.random() * (max - min + 1)) + min;
        }
         
        // 生成一个随机的十六进制的值,在 0 ~ f 之间
        function getHex() {
          let n = 0;
          for (let i = 4; i > 0; i--) {
            n = (getRandomInt(0, 1) << (i - 1)) + n;
          }
          return n.toString(16);
        }
         
        // 生成一个32位的十六进制值,用作一次性 Key
        function getOTP() {
          const arr = [];
          for (let i = 0; i < 32; i++) {
            arr.push(getHex());
          }
          return arr.join('');
        }

上面代码中,生成的 key是32位的十六进制值,对应 MD5 产生的128位的二进制哈希

第三步,进行 XOR 运算,求出加密后的message。

        function getXOR(message, key) {
          const arr = [];
          for (let i = 0; i < 32; i++) {
            const  m = parseInt(message.substr(i, 1), 16);
            const k = parseInt(key.substr(i, 1), 16);
            arr.push((m ^ k).toString(16));
          }
          return arr.join('');
        }

使用这种方法保存用户的登陆密码,即使加密文本泄露,只要一次性的密钥(key)没有泄露,对方也无法破解。

(完)

 异或加密算法

异或加密是一种很简单的加密算法,无论是原理还是操作性上,都不具备任何难度,所以,在做一些简单的加密时,被广为采用。

但因为很简答,破解起来也很容易,所以对于更加私密的信息,不要用这种方法加密。

下面我们简单地介绍一下异或的运算:

数学运算符为XOR(exclusive OR),在计算机中通常用"^"的符号表示(在英文模式下,按住shift键+键盘上方的数字6)

在二进制中:

1 XOR 0=1

0 XOR 1=1

1 XOR 1=0

0 XOR 0=0

可以看出若两个数相同取0,不同取1。

例:

运算11001 ^ 01011=10010

用其他进制表示的数做异或运算时,则应先将他们化为二进制的数,再做运算。(不足的位在前边填0补齐)

例:

计算6^3=110^011=101

*******************************************************

异或运算具有可逆性。

即:若a^b=c,则有b^c=a (a,b,c分别表示0或1)

利用前面的异或运算规则,我们就其中之一分析:

1 XOR 0=1        则     0 XOR 1=1

原理:根据异或的运算规则,相同为0,不同为1;

若两个数a,b相同,a=b,则用任意一个数与0做异或时,即得到这个数本身,也就是另一个数;

应用 1 XOR 0 = 1  ,  0 XOR 0= 0 这两个运算规则(相当于取这个数)。

若两个数a,b不同,a=~b,则用任意一个数与1做异或时,即得到这个数的相反,也就是另一个数

应用 1 XOR 1 = 0  ,  0 XOR 1 = 1 这两个运算规则(相当于对这个数取反)。  

**********************************************************

我们不妨对异或的可逆性进行推广,对任意的两串二进制数做异或,得到的结果,再与其中任意一串二进制数做异或,得到另一串二进制数。

即a^b=c , 则 b^c=a.(a,b,c分别表示一串二进制数)

与上面的公式形式上是相同的。

那么,若a是想要加密的信息,则有一密钥b,对a和b做异或,得到的c就是加密后的信息,可进行传输。

得到c后,只需要再 与b做异或,即可得到原信息a。

若应用到字符串上,则字符串上每一个字符都表示一串二进制数。

例:

#include <stdio.h>
main()
{
   char a[]="Password";        //要加密的密码(明文密码,需要进行加密的原始字符串)
   char b[]="encryption";     //密钥(加密所要使用的密码,加密与解密的密码)
   int i;

   
   //加密代码
   for(i=0;a[i];i++)
     a[i]=a[i]^b[i];
   printf("Your Password is encrypted: %s\n",a);

   
   /*解密代码*/
   for(i=0;a[i];i++)
      a[i]=a[i]^b[i];
   printf("You Password: %s\n",a);
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值