前言:数据安全
数据的**加密解密操**作在 日常网络交互中经常会用到,**现在密码的安全主要在于**** 秘钥的安全****,如论 DES 3DES AES 还是 RSA, 秘钥的算法(****计算秘钥不固定****) 和 保存,都决定了你的数据安全;但是常见的逆向操作 ** 比如 **hook 加密算法**都很容易拿到 秘钥; 这个时候我们可以 **回溯到 之前的 古典密码学**(**依赖算法本身**),基本思路 ** 置换 移位 编码** 等等手段 来配合 **加密算法一起使用,提高我们应用的安全**;
密码学概论_在传统的密码学中,加解密基础操作包括移位置换替换编码-CSDN博客文章浏览阅读201次。密码学基础_在传统的密码学中,加解密基础操作包括移位置换替换编码https://blog.csdn.net/nicepainkiller/article/details/132978492?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170902384916777224453245%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=170902384916777224453245&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-132978492-null-null.nonecase&utm_term=%E5%AF%86%E7%A0%81&spm=1018.2226.3001.4450
android frida 逆向 自吐加密算法_frida 自吐算法 教程-CSDN博客文章浏览阅读1.8k次。frida hook android Android 逆向神器_frida 自吐算法 教程https://blog.csdn.net/nicepainkiller/article/details/132554698?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170902437216800182198144%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=170902437216800182198144&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-132554698-null-null.nonecase&utm_term=hook&spm=1018.2226.3001.4450
flutter 数据加密
如果是 android 原生应用,可以 hook 系统加密代码,来获取加密秘钥,而在 flutter 中,dart 是被直接编译为 .so 文件,也就是汇编,对于低级汇编语言 可读性大大降低。当然也是可以下断点动态调试的;但是相对于难度 大大增加,我们可以结合 古典密码学 主要特点 数据安全基于算法的保密,算法不公开, 设计繁琐的算法过程,增加汇编可读性难度;
有个业务需求是:相当于是一个签到功能,每天可以领取,这里防止脚本调用使用两层 基于算法加密 和 AES加密 相结合的方式;(当然还用到了第三方的的安全软件)
以下是我上个版本加密算法设计:整体思路就是:
- 按照规则 移动字符 替换字符
- 阶段一主要是 按规则打乱字符(密文)位置
- 阶段二主要是 指定位置(密文)插入无关字符
match_request_data.dart
import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:encrypt/encrypt.dart' as encrypt;
///匹配接口加密工具类
///整体加密思路:按照规则 移动字符 替换字符
///阶段一主要是 按规则打乱字符位置
///阶段二主要是 指定位置插入无关字符
class MatchRequestData {
final String gameId;
final String chatSign;
final String nickName;
late List<int> _gameIdSort;
MatchRequestData(
{required this.gameId, required this.chatSign, required this.nickName});
String generateCode(String datum) {
String idStr = '${int.parse(gameId)}';
List<int> searchKeywords =
List<int>.generate(idStr.length, (index) => int.parse(idStr[index]));
searchKeywords.sort();
_gameIdSort = searchKeywords;
String base64 = _encodeBase64(datum);
String base64Step0 =
base64.substring(0, _gameIdSort[_gameIdSort.length - 1]) +
_stepOne((base64.substring(
_gameIdSort[_gameIdSort.length - 1],
base64.length -
_gameIdSort[3] -
_gameIdSort[_gameIdSort.length - 1]))) +
base64.substring(base64.length -
_gameIdSort[3] -
_gameIdSort[_gameIdSort.length - 1]);
String _strHex = _strToHex(base64Step0);
final key = encrypt.Key.fromUtf8(_generateMd5(chatSign + nickName));
final iv = encrypt.IV.fromUtf8(_ivStepOne().substring(4, 20).toUpperCase());
final encrypter =
encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc));
final encrypted = encrypter.encrypt(_strHex, iv: iv);
final encryptCode = _stepTwo(encrypted.base64);
idStr = _strHex = base64 = base64Step0 = '';
return encryptCode;
}
String _stepOne(String str) {
String res = '';
str = _inverse(str);
int lastPosition = _gameIdSort[_gameIdSort.length - 1];
int count = 0;
if (lastPosition % 2 == 0) {
count = _gameIdSort[_gameIdSort.length - 2];
} else {
count = _gameIdSort[_gameIdSort.length - 3];
}
if (count == 0) {
count = lastPosition;
}
int step = str.length ~/ count;
List<String> base64Parts = [];
for (int i = 0; i < count; i++) {
if (i % 2 == 1) {
base64Parts.add(_inverse(str.substring(step * i, step * (i + 1))));
} else {
base64Parts.add(str.substring(step * i, step * (i + 1)));
}
}
if (step * count < str.length) {
if (lastPosition % 2 == 0) {
base64Parts.insert(0, str.substring(step * count));
} else {
base64Parts.insert(base64Parts.length, str.substring(step * count));
}
}
if (lastPosition % 2 == 1) {
for (int i = 0; i < base64Parts.length; i++) {
res = res + base64Parts[i];
}
} else {
for (int i = base64Parts.length - 1; i >= 0; i--) {
res = res + base64Parts[i];
}
}
str = '';
lastPosition = count = step = -1;
return res;
}
String _stepTwo(String data) {
String res = "";
String _strHex = _strToHex(data);
String _code = _inverse(_strHex);
final key = encrypt.Key.fromUtf8(_generateMd5(gameId + chatSign));
final iv = encrypt.IV.fromUtf8(_ivStepTwo().substring(14, 30));
final encrypter =
encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc));
final encrypted = encrypter.encrypt(_code, iv: iv);
res = encrypted.base64;
int maxLength = res.length;
int indexSub = 0;
int insertPos = 0;
String insertStr = '';
for (int i = 1; i < _gameIdSort.length; i++) {
indexSub = _gameIdSort[i] + 1;
insertPos = _magic(indexSub + i) + i * 11 + i - 1;
// insertStr = chatSign.substring(1,indexSub);
insertStr = chatSign[indexSub];
//前面插入
if (insertPos > res.length) {
insertPos = maxLength;
}
res =
'${res.substring(0, insertPos)}$insertStr${res.substring(insertPos)}';
}
_strHex = _code = '';
return res;
}
String _stepThree(String str) {
return str;
}
String _inverse(String tag) {
String res = '';
List<String> searchKeywords =
List<String>.generate(tag.length, (index) => tag[index]);
Iterable<String> array = searchKeywords.reversed;
for (var e in array) {
res = '$res$e';
}
return res;
}
String _ivStepOne() {
String res = '';
String map = _generateMd5(chatSign) + _generateMd5(nickName);
int index = _gameIdSort[_gameIdSort.length - 2];
while (res.length < 50) {
res += map[index];
index++;
}
index = 0;
return res;
}
String _ivStepTwo() {
String res = '';
String map = _generateMd5(_inverse(chatSign)) + _generateMd5(chatSign);
int index = _gameIdSort[_gameIdSort.length - 1];
while (res.length < 50) {
res += map[index];
index++;
}
index = 0;
return _inverse(res);
}
/// 字符串转 十六进制
String _strToHex(String str) {
List<int> charCodes = str.runes.toList();
return charCodes.map((code) => code.toRadixString(16)).join('');
}
/// 字符串转 base64
String _encodeBase64(String data) {
return base64Encode(utf8.encode(data));
}
/// base64转 普通字符
String _decodeBase64(String data) {
return String.fromCharCodes(base64Decode(data));
}
String _generateMd5(String str) {
return md5.convert(utf8.encode(str)).toString();
}
int _magic(int num) {
if (num < 3) {
return 1;
} else {
return _magic(num - 1) + _magic(num - 2);
}
}
}
调用的地方:
MatchRequestData data = MatchRequestData (
gameId: userArray[i]['gameID'],
chatSign: userArray[i]['chatSign'],
nickName: userArray[i]['nickName'],
);
//需要传递给后台的 内容
Map datum = {
'inTrust': 'TRUE',
'time': DateTime.now().millisecondsSinceEpoch,
'GameID': userArray[i]['gameID'],
'nickName': userArray[i]['nickName'],
'MachineCode':
md5.convert(utf8.encode(userArray[i]['gameID'])).toString(),
'sign': md5
.convert(
utf8.encode(userArray[i]['gameID'] + userArray[i]['chatSign']))
.toString(),
};
String res = data.generateCode(jsonEncode(datum));
服务端的数据解密:
服务端为 .net 框架:
对应于加密算法写的解密算法:
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
namespace ToMatch
{
public class MatchEncrypt
{
private string gameID;
private string chatSign;
private string nickName;
private List<int> idSort;
/// <summary>
/// 匹配构造函数
/// </summary>
/// <param name="gameId">GameID</param>
/// <param name="chatSign">签名</param>
/// <param name="nickName">昵称</param>
public MatchEncrypt(string gameId, string chatSign, string nickName) {
this.gameID = gameId;
this.chatSign = chatSign;
this.nickName = nickName;
this.idSort = new List<int>();
string idStr = int.Parse(this.gameID).ToString();
for (int i = 0; i < idStr.Length; i++)
{
this.idSort.Add((int)Char.GetNumericValue(idStr[i]));
}
this.idSort.Sort();
}
private String IvStepOne {
get {
String res = "";
String map = Md5Hash(chatSign) + Md5Hash(nickName);
int index = idSort[idSort.Count - 2];
while (res.Length < 50)
{
res += map[index];
index++;
}
return res;
}
}
private String IvStepTwo
{
get
{
String res = "";
String map = Md5Hash(AESHelper.Inverse(chatSign),false) + Md5Hash(chatSign,false);
int index = idSort[idSort.Count - 1];
while (res.Length < 50)
{
res += map[index];
index++;
}
return AESHelper.Inverse(res);
}
}
/// <summary>
/// 解密客户端内容
/// </summary>
/// <param name="code">密文</param>
/// <returns></returns>
public string Resolver(string code) {
//第一阶段解密内容
string resStepOne = StepOne(code);
if (resStepOne.Length > 0)
{
//Console.WriteLine("第一解密 result:" + resStepOne);
//第二阶段解密
string resSteptwo = Steptwo(resStepOne);
//Console.WriteLine("第二解密 result:" + resSteptwo);
//Console.WriteLine(AESHelper.FromBase64(resSteptwo));
if (resSteptwo.Length > 0)
{
return AESHelper.FromBase64(resSteptwo);
}
else
{
return "解密失败——请记录日志.Step-2";
}
}
else {
return "解密失败——请记录日志.Step-1";
}
}
private string StepOne(string code)
{
// 1.先移除插入的字符
// 2.再进行解密操作
int maxlength = code.Length - idSort.Count - 1;
int indexSub = 0;
int insertPos = 0;
for (int i = 1; i < idSort.Count; i++)
{
indexSub = idSort[i] + 1;
insertPos = magic(indexSub + i) + i * 11;
//前面插入
//Console.WriteLine("前面 索引:" + i);
//Console.WriteLine("前面插入位置:" + insertPos);
//Console.WriteLine("前面插入字符:" + insertStr + "");
if (insertPos > code.Length) {
//Console.WriteLine("修正Length:" + code.Length);
Console.WriteLine("修正insertPos:" + insertPos);
//Console.WriteLine("----code.Length:" + (code.Length -maxlength ));
//Console.WriteLine("----code.Length:" + ( idSort.Count-1 - i));
//Console.WriteLine("----code.Length:" + ((code.Length - maxlength - (idSort.Count - 1 - i))+1));
insertPos = maxlength -4;
insertPos = maxlength - ((code.Length - maxlength - (idSort.Count - 1 - i)) + 1);
//Console.WriteLine("*******code.Length:" + ((code.Length - maxlength - (idSort.Count - 1 - i)) + 1));
//Console.WriteLine("*******code.Length:" + (code.Length - maxlength - (idSort.Count - i)) );
//Console.WriteLine("*******code.Length:" + (code.Length - maxlength - idSort.Count - i ));
//Console.WriteLine("code.Length:" + code.Length);
//Console.WriteLine("maxlength:" + maxlength);
//Console.WriteLine("idSort.Count:" + idSort.Count);
//Console.WriteLine("idSort.Count - i:" + (idSort.Count - i));
//Console.WriteLine("修正插入位置i:" + i);
//Console.WriteLine("修正插入位置:" + insertPos);
insertPos = maxlength - ((code.Length - maxlength - (idSort.Count - 1 - i)) + 1);
}
code = code.Substring(0, insertPos) + code.Substring(insertPos + 1);
}
//Console.WriteLine("整理后的:" + code);
//Console.WriteLine("整理后的Length:" + code.Length);
string key = Md5Hash(this.gameID + this.chatSign, false);
string iv = IvStepTwo.Substring(14, 16);
//第一次解密是 16进制字符串
string result = AESHelper.Decrypt(code, key, iv);
return AESHelper.HexStringToString(AESHelper.Inverse(result), Encoding.UTF8);
}
private string Steptwo(string code) {
string key = Md5Hash(this.chatSign + this.nickName, false);
string iv = IvStepOne.Substring(4, 16);
string base64 = AESHelper.HexStringToString(AESHelper.Decrypt(code, key, iv), Encoding.UTF8);
string source = base64.Substring(0, idSort[idSort.Count - 1]) + generateMid(base64.Substring(idSort[idSort.Count - 1], base64.Length - idSort[3] - idSort[idSort.Count - 1] * 2)) + base64.Substring(base64.Length - idSort[3] - idSort[idSort.Count - 1]);
//第二次解密是 base64
return source ;
}
private string generateMid(string str) {
string res = "";
List<String> base64Parts = new List<string>();
int lastPosition = this.idSort[this.idSort.Count - 1];
string subBefore = "";
int count = 0;
if (lastPosition % 2 == 0)
{
count = idSort[idSort.Count - 2];
}
else
{
count = idSort[idSort.Count - 3];
}
if (count == 0) {
count = lastPosition;
}
int step = str.Length / count;
int subLength = str.Length - step * count;
if (lastPosition % 2 == 0)
{
for (int i = 0; i < count; i++)
{
if (i % 2 == 1)
{
base64Parts.Add(AESHelper.Inverse(str.Substring(step * (count - i - 1), step)));
}
else
{
//base64Parts.Add(v.Substring(step * i, step));
//Console.WriteLine(i + "不需要翻转原始:" + str.Substring(step * (count - i - 1), step));
base64Parts.Add(str.Substring(step * (count - i - 1), step));
}
}
for (int i = 0; i < base64Parts.Count; i++)
{
//Console.WriteLine("偶数项目:" + i + " " + base64Parts[i]);
res = res + base64Parts[i];
}
subBefore = str.Substring(step * count);
res += subBefore;
}
else
{
for (int i = 0; i < count; i++)
{
if (i % 2 == 1)
{
base64Parts.Add(AESHelper.Inverse(str.Substring(step * i, step)));
}
else
{
base64Parts.Add(str.Substring(step * i, step));
}
}
subBefore = str.Substring(step * count);
base64Parts.Add(subBefore);
for (int i = 0; i < base64Parts.Count; i++)
{
//Console.WriteLine("奇数项目:" + i + " " + base64Parts[i]);
res = res + base64Parts[i];
}
}
return AESHelper.Inverse(res);
}
private static int magic(int num)
{
if (num < 3)
{
return 1;
}
else
{
return magic(num - 1) + magic(num - 2);
}
}
private string Md5Hash(string sourceText, bool toUpper = true)
{
StringBuilder result = new StringBuilder();
using (MD5 md5 = new MD5CryptoServiceProvider())
{
byte[] data = md5.ComputeHash(Encoding.UTF8.GetBytes(sourceText));
if (toUpper)
for (int i = 0; i < data.Length; i++)
result.Append(data[i].ToString("X2"));
else
for (int i = 0; i < data.Length; i++)
result.Append(data[i].ToString("x2"));
}
return result.ToString();
}
}
}
总结
数据安全不是绝对的,只能说我们多设置些障碍,对于逆向的难度对增大,你挖的坑多远。逆向时候就越困难,当然也可以借助一些第三方安全软件来增加我们数据的安全性。在数据安全的道路上 始终是此消彼长的状态
版权归原作者 坎大哈 所有, 如有侵权,请联系我们删除。