原理
基于分组加密
加密过程

Plaintext:明文,待加密的数据。
IV:用于随机化加密的比特块,保证即使对相同明文多次加密,也可以得到不同的密文,初始向量,用来与第一块的明文异或运算。
Key:被一些如AES的对称加密算法使用。
Ciphertext:密文,加密后的数据。
在这里重要的一点是,CBC工作于一个固定长度的比特组,将其称之为块。在本文中,我们将使用包含16字节的块。
• Ciphertext-0 = Encrypt(Plaintext XOR IV)—只用于第一个组块
• Ciphertext-N= Encrypt(Plaintext XOR Ciphertext-N-1)—用于第二及剩下的组块
XOR为异或运算 , N为第N块数据
---------------------------------------------------------------------------
上述的公式和图可以简单描述为:
1.将要CBC加密的数据分为N个块,每个块为16字节
2.随机找一个IV(初始向量),大小为每个块的大小(16字节),用于与第一个块进行异或运算
3.将异或运算的结果进行选定的加密方式进行加密
4.将得到的第一块密文与第二块明文进行异或运算
5.将异或运算的结果进行选定的加密方式进行加密
6.将得到的第二块密文与第三块明文进行异或运算
7.将异或运算的结果进行选定的加密方式进行加密
8.最后得到三块加密获得的密文
注意:正如你所见,前一块的密文用来产生后一块的密文。
----------------------------------------------------------------------
解密过程
Decryption Process

• Plaintext-0 = Decrypt(Ciphertext) XOR IV—只用于第一个组块
• Plaintext-N= Decrypt(Ciphertext) XOR Ciphertext-N-1—用于第二及剩下的组块
• -----------------------------------------------------------------------------------
上述的公式和图可以简单描述为:
1.将已经CBC加密的数据分为N个块,每个块为16字节
2.将第一块加密的数据用选定的加密方式解密
3.找到加密时的IV,用于与第一个解密后的块进行异或运算,得到第一块的明文
4.将第二块加密数据进行解密
5.用第一块加密的密文与第二块解密的块进行异或运算,得到第二块的明文
6.将第三块加密的数据进行解密
7.用第二块加密的数据与第三块解密的块进行异或运算,得到第二块的明文
通过上述的解密过程可以推算出:
如果要修改第二个块中的第n个字节的数据,只要修改第一块数据的密文中的第n个字节数据,这样第一个块的密文与第二个块解密得到的数据进行异或运算时就可以得到自己想要的数据,对第三个块及其以后的数据都不会产生影响(因为与下一块进行异或运算的都是加密的数据,第二块的加密数据没有进行改变),但是第一个块修改了加密数据,进行解密和与IV异或运算后会产生错误数据。
以此类推,如果要修改第三块中的数据,就修改第二块的加密信息,会产生错误数据的只有第二块数据,其他块的数据不会产生错误。
如果要修改第一块的数据的话,只能修改第一块密文,这需要知道IV是什么,过程:
1.将第一块的明文修改成想要的数据
2.将修改完的数据与IV进行异或运算,然后进行选定方式的加密,得到密文数据
3.将第一块的密文数据换成的到的密文数据
这样的话会出现错误的块是第二块,因为第一块的密文修改了,与第二块的已解密的数据进行异或运算时产生错误。
解决错误的方式是修改IV
-----------------------------------------------------------------------------
注意:Ciphertext-N-1(密文-N-1)是用来产生下一块明文;这就是字节翻转攻击开始发挥作用的地方。如果我们改变Ciphertext-N-1(密文-N-1)的一个字节,然后与下一个解密后的组块异或,我们就可以得到一个不同的明文了!You got it?别担心,下面我们将看到一个详细的例子。与此同时,下面的这张图也可以很好地说明这种攻击:

0x02 一个例子(CBC Blocks of 16 bytes)

比方说,我们有这样的明文序列:
a:2:{s:4:"name";s:6:"sdsdsd";s:8:"greeting";s:20:"echo 'Hello sdsdsd!'";}
我们的目标是将“s:6”当中的数字6转换成数字“7”。我们需要做的第一件事就是把明文分成16个字节的块:
• Block 1:a:2:{s:4:"name";
• Block 2:s:6:"sdsdsd";s:8
• Block 3::"greeting";s:20
• Block 4::"echo 'Hello sd
• Block 5:sdsd!'";}
因此,我们的目标字符位于块2,这意味着我们需要改变块1的密文来改变第二块的明文。
有一条经验法则是(注:结合上面的说明图可以得到),你在密文中改变的字节,只会影响到在下一明文当中,具有相同偏移量的字节。所以我们目标的偏移量是2:
• [0] = s
• [1]= :
• [2] =6
因此我们要改变在第一个密文块当中,偏移量是2的字节。正如你在下面的代码当中看到的,在第2行我们得到了整个数据的密文,然后在第3行中,我们改变块1中偏移量为2的字节,最后我们再调用解密函数。
1. $v = "a:2:{s:4:"name";s:6:"sdsdsd";s:8:"greeting";s:20:"echo 'Hello sdsdsd!'";}";
2. $enc = @encrypt($v);
3. $enc[2] = chr(ord($enc[2]) ^ ord("6") ^ ord ("7"));
4. $b = @decrypt($enc);
运行这段代码后,我们可以将数字6变为7:

但是我们在第3行中,是如何改变字节成为我们想要的值呢?
基于上述的解密过程,我们知道有,A = Decrypt(Ciphertext)与B = Ciphertext-N-1异或后最终得到C = 6。等价于:
C = A XOR B
所以,我们唯一不知道的值就是A(注:对于B,C来说)(block cipher decryption);借由XOR,我们可以很轻易地得到A的值:
A = B XOR C
最后,A XOR B XOR C等于0。有了这个公式,我们可以在XOR运算的末尾处设置我们自己的值,就像这样:
A XOR B XOR C XOR "7"会在块2的明文当中,偏移量为2的字节处得到7
--------------------------------------------------------------------
异或计算的公式:
1.A XOR B =C ,       B XOR C=A,       A XOR C =B
2.A XOR B XOR C =0

3.0 XOR A = A
----------------------------------------------------------------

Demo

目前自己测试只能修改第二块和第一块数据
源码:
 function login($info){
      $iv = get_random_iv();
     $plain = serialize($info);
     $cipher = openssl_encrypt($plain, aes-128-cbc, SECRET_KEY, OPENSSL_RAW_DATA, $iv);
      $_SESSION['username'] = $info['username'];
      setcookie("iv", base64_encode($iv));
     setcookie("cipher", base64_encode($cipher));
 }
  function check_login(){
      if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])){
          $cipher = base64_decode($_COOKIE['cipher']);
          $iv = base64_decode($_COOKIE["iv"]);
          if($plain = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)){
              $info = unserialize($plain) or die("<p>base64_decode('".base64_encode($plain)."') can't unserialize</p>");
              $_SESSION['username'] = $info['username'];
          }else{
              die("ERROR!");
          }
      }
  }
 if(isset($_POST['username']) && isset($_POST['password'])){
      $username = (string)$_POST['username'];
      $password = (string)$_POST['password'];
      if($username === 'admin'){
          exit('<p>admin are not allowed to login</p>');
      }else{
          $info = array('username'=>$username,'password'=>$password);
          login($info);
          show_homepage();
      }
  else{
      if(isset($_SESSION["username"])){
          check_login();
          show_homepage();
      }

输入用户名admir密码1,抓取数据内容为:
Cookie:
PHPSESSID=iq1lrnq2fhp235ndd4ke2njl73;
iv=XyP2qyLI00SzmCP8t766mA%3d%3d;
cipher=8Rhxwqez6NPucPx4mKM4oytL0QCEM6YnRhjkPTjIVvDMp8HAF2%2f8JjiWG8oSLqwgdGs4EV018W7SU63K3bYV9w%3d%3d

过程: XOR异或 、CRYPT加密(未知密钥)、en-加密后
plain XOR iv ->after_plain   CRYPT ->en-after_plain

补充:AES加密后的数据为16字节的整数倍,可直接进行异或运算

解题过程:
<?php
$enc=base64_decode("bIpgPK29vVQosJ+smzh0pOdq7QrP3H9CN0MBfynL1eKtILs/ayew1snTYbeYSIz8rQctkAUMORS76SWQHXwuKg==");
$enc[13] = chr(ord($enc[13]) ^ ord("k") ^ ord ("n"));
echo base64_encode($enc);
?>
 
<?php
$enc=base64_decode("4quudO++PAeVPQfcFJ0bbm1lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjM6IjEyMyI7fQ==");
$iv=base64_decode("TrphJjWLH37sj6+EBqh28A==");
$cleartext = 'a:2:{s:8:"userna';
$newiv = '';
for ($i=0;$i<16;$i++){
    $newiv=$newiv.chr(ord($iv[$i]) ^ ord($enc[$i]) ^ ord ($cleartext[$i]));
}
echo base64_encode($newiv);
?>
详解:
    1. $enc = en-after_plain
    2. 因为序列化的内容为
    a:2:{s:8:"userna
    me";s:5:"admik";  
    s:8:"password";s
    :1:"1";}
    所以修改块二上的第13位数据(从0开始),因此修改块一13位数据(AES加密)
    3. 修改数据计算:

1.算法
    ciphertext XOR plaintext  = 加密前xor后的plain
    加密前xor后的plain XOR plaintext =ciphertext
    所以比如要修改enc[23]处的值时,使用的算法为enc[7]^"替换前"^"替换后"
注意错误:不能使用加密后直接异或,从过程来看就为错误
          例如enc[23]^"H"就是错误的,因为加密后原本异或后位置的字符改变
    2.关于改变后iv的获得
    由于数据改变导致第一块数据异或时得到不能序列化的数据,所以需要根据网页返回的不能序列化的数据(也就是除iv修改完后块一的数据,base64解码后就是序列化数据)进行异或运算来的得到新的iv
    与前面的1 运算相同
    iv XOR 网页返回的数据 = 加密前xor后的plain(序列化错误的)
    加密前xor后的plain XOR plain(正常序列的) = new_iv
    所以得到iv算法为  iv ^ wrong_plain ^ plain
    补充:由于加密解密得关系 所以不只是特定位置的字符错误,需要全部异或计算

CBC加密原理及攻击的更多相关文章

  1. 分组密码CBC加密缺陷

    title: 分组密码CBC加密缺陷 date: 2017-05-15 10:04:47 tags: ["密码学"] --- 关于密码学的种种漏洞以及利用网上也有不少,但是比较零散 ...

  2. Atitit RSA非对称加密原理与解决方案

    Atitit RSA非对称加密原理与解决方案 1.1. 一.一点历史 1 1.2. 八.加密和解密 2 1.3. 二.基于RSA的消息传递机制  3 1.4. 基于rsa的授权验证机器码 4 1.5. ...

  3. Java实现SSH模式加密原理及代码

    一.SSH加密原理 SSH是先通过非对称加密告诉服务端一个对称加密口令,然后进行验证用户名和密码的时候,使用双方已经知道的加密口令进行加密和解密,见下图: 解释:SSH中为什么要使用非对称加密,又使用 ...

  4. HTTPS加密原理与过程

    HTTPS加密原理与过程 HTTP 超文本传输协议一种属于应用层的协议 缺点: 通信使用明文(不加密),内容可能会被窃听 不验证通信方的身份,因此有可能遭遇伪装 无法证明报文的完整性,所以有可能已遭篡 ...

  5. 密码学——网间数据加密传输全流程(SSL加密原理)

    0.导言 昨天写了一篇关于<秘钥与公钥>的文章,写的比较简单好理解,有点儿像过家家,如果详细探究起来会有不少出入,今天就来详细的说明一下数据加密的原理和过程.这个原理就是大名鼎鼎SSL的加 ...

  6. 一篇读懂HTTPS:加密原理、安全逻辑、数字证书等

    1.引言 HTTPS(全称: Hypertext Transfer Protocol Secure,超文本传输安全协议),是以安全为目标的HTTP通道,简单讲是HTTP的安全版.本文,就来深入介绍下其 ...

  7. AES加密解密 助手类 CBC加密模式

    "; string result1 = AESHelper.AesEncrypt(str); string result2 = AESHelper.AesDecrypt(result1); ...

  8. SHA-256 加密原理

    网络中传输敏感信息的时候通常会对字符串做加密解密处理 SHA-256 加密原理

  9. HTTPS加密原理(转)

    Header HTTP.HTTPS在我们日常开发中是经常会接触到的. 我们也都知道,一般 Android 应用开发,在请求 API 网络接口的时候,很多使用的都是 HTTP 协议:使用浏览器打开网页, ...

随机推荐

  1. IDEA中常用优化设置

    1.设置鼠标悬浮提示 Editor->General 这里要勾选下,后面设置的是延迟时间 默认半秒:设置后,我们鼠标移动到类上看看: 2.显示方法分隔符 Editor->General - ...

  2. jquery中 $(xxx).each() 和 $.each()的区别,以及enter键一键登录

    1.$().each 在dom处理上面用的较多.如果页面有多个input标签类型为text,对于这时用$().each来处理多个text,例如: $("input[type=’text’]& ...

  3. Python 爬取 热词并进行分类数据分析-[热词关系图+报告生成]

    日期:2020.02.05 博客期:144 星期三 [本博客的代码如若要使用,请在下方评论区留言,之后再用(就是跟我说一声)] 所有相关跳转: a.[简单准备] b.[云图制作+数据导入] c.[拓扑 ...

  4. PAT T1001 Battle Over Cities-Hard Version

    按题意枚举每个点,建立缺少该点情况下的最小生成树,取权值最大的~ #include<bits/stdc++.h> using namespace std; ; const int inf= ...

  5. Java基础知识笔记第十章:输入输出流

    File类 文件的属性 目录 文件的创建与删除 运行可执行文件 文件字节输入流 文件字节输出流 文件字符输入输出流 缓冲流 随机流 数组流 数据流 对象流 序列化与对象克隆 使用Scanner解析文件 ...

  6. 吴裕雄--天生自然PythonDjangoWeb企业开发:解决使用相对路径名导入包中子模块问题

    问题 将代码组织成包,想用import语句从另一个包名没有硬编码过的包中导入子模块. 解决方案

  7. 关于盒模型的外边距padding和内边距margin

    边框border属性值  solid实线   dashed虚线   dotted点线   double双实线 /* 内边距 */padding:20px 30px 30px 30px;若有四个值代表  ...

  8. c++中的运算符重载operator2(翁恺c++公开课[31-33]学习笔记)

    上一篇operator1中,大概说了下重载的基本用法,接下来对c++中常见的可重载运算符归一下类,说一下它们的返回值,讨论下较为复杂的运算符重载上的坑

  9. LeetCode 345. Reverse Vowels of a String(双指针)

    题意:给定一个字符串,反转字符串中的元音字母. 例如: Input: "leetcode" Output: "leotcede" 法一:双指针 class So ...

  10. sshd免密登陆

    用途:默认情况下,当A主机(1.1.1.1)远程通过ssh命令登陆到B主机(2.2.2.2)上,需要输入B主机的密码.免密登陆的效果为,A通过ssh命令登录到B时,不需要输入密码就可以登录,便于管理. ...