Ascii码加密编码

  1. Ascii码加密编码
    1. 前言
    2. 算法设计
    3. 解密
    4. 织入密码
    5. 代码实现

Ascii码加密编码

前言

最近在做字符串工具类的时候发现可以封装下SHA256加密算法,但发现好像不太会用

突发奇想自己是不是也可以做一个简单的加密算法,相比于非对称加密,对称加密的规则还是比较好制定的。

由于每个字符都对应着一个Ascii码值(0 ~ 65535) ,因此对字符进行逻辑算术运算是很轻松的。

既然如此,我们可以想象一下,如果要保证信息不丢失,我们的密文只需要带有先前的信息进行加密并且不造成信息损失即可。

信息损失都有哪些?比如精度的丢失,多对一的映射关系等

算法设计

现在要解决的是如何设计算法

  • 想象一下,平常我们的文件是否经常出现乱码的问题,那就是因为我们解码的算法有错误,或者是没有找到合适的密码进行解密

  • 类比一下,我们可以这样设计算法,将当前的字符串进行遍历,每个字符都通过某个规则映射到ascii码表中的另一个字符,当我们需要解密时,只需要逆着这个规则反推,即可从加密后的乱码推回原来的明文了

  • 那么接下来只需要制定规则即可

  • 我们希望加密的过程是动态的,即每一步加密都依赖于上一次加密的数据,这样的好处在于只要明文的内容中间有增删改都会对整体的加密效果产生影响

  • 如何实现动态的加密?

    • 其实也不难想,我们在第一次加密的时候使用原始数据对第一个字符进行加密,此时我们就拥有了一个经过算法加密后的字符

    • 加密第二个字符的时候我们就可以不使用原始数据了,为了实现动态加密,我们可以使用上一个已经被加密的字符作为本次字符加密的映射规则变量

      映射规则变量: 我们的ascii码映射规则可以通过简单的基本运算对明码进行ascii码偏移,从而得到密码,而映射规则变量就作为改规则基本运算的变量使用

因此我们可以设计出简单的流程

​ 我们要加密的字符串为 java

​ 取第一个字符j 和最后一个 字符 a,让j (ascii 106) 在ascii码表上向右偏移 a对应ascii码 (ascii 97) 个位置

​ 此时我们我们得到新的密文所对应ascii码值应该为 106 + 97 = 203,将此字符放在j 所对应的索引位置即可(可以新建一个数组来存放密文ascii值),此时我们继续加密第二个a为了使得逻辑具备复杂性,我们可以在这次加密使用左偏移a 字符在ascii表上向左203 个位置,得到新字符ascii值

溢出范围问题

​ 此时我们发现了一个问题(ascii码的值只在0~65535间),这次左偏移明显会得到 93 - 203 = -110 的负值,其实也不用担心,我们可以假想一下我们的ascii码存在于这样一条纸带上 … 0,1,2…65535,0,1,2….65535… ,这样不断循环纸带上即可将负数部分的映射关系转换为 -1 → 65535,-2 → 65534 ….,这样我们就得到了 -110 → 65535 + 1 - 110 = 65426 对应ascii的字符,同理,在超出65535的部分我们也可以这样映射, 65536 → 1 ,65537 → 2

解决完溢出问题后,我们就使用了第一个字符加密后的值作为新的映射规则变量成功加密了第二个字符a

接着我们加密v,然后加密a

此时我们得到了加密的密文ascii数组 203 65430 12 85 ,我们可以使用第一轮加密的密文作为新的明文进行新一轮加密,多轮加密后复杂度就得到了提升

3轮加密下的ascii值偏移

  • 203 65430 12 85
  • 288 65142 65154 467
  • 755 64387 64005 1998

java 进行 加密后变为 ˳ ﮃ 洞 ߎ

解密

解密就是一个逻辑的逆向过程,只要编码过程中没有出现信息损失,我们只要逆着逻辑来就能反推回原来的信息

我们从密文最后一个位置的字符开始解密,判断之前此位置字符是左移还是右移过来的,我们通过倒数第二个字符就能知道偏移量是多少

由于是先加密完倒数第二个字符然后再加密倒数第一个字符,因此倒数第二个字符即为倒数第一个字符的偏移信息

逆向偏移后我们就解密了一次字符,然后再解密倒数第二个字符…依次解密到第一个字符,此时解密完的只是第一层密文,我们还需要逆推多次才能得到最初始的明文。

织入密码

当然这种加密也仅仅只是一种动态编码的方法,并没有真正织入密码,其实织入密码的方法也很容易,我们将事先提供的密码明文经过编码后将密码编码值经过运算得到新的偏移量,从而实现加密处理

当然这种加密在理论上可能会存在撞库解析的风险

代码实现

基于字符串类型的加密

之后实现比特类型的加密


public class AsciiEncodingStringUtils extends StringUtilsImpl {

    public static final int MAX_CHARACTER = Integer.valueOf(Character.MAX_VALUE);

    public static final int MIN_CHARACTER = Integer.valueOf(Character.MIN_VALUE);

    public static final int ROOT_VALUE = 467;

    public AsciiEncodingStringUtils(String str) {
        super(str);
    }

    //密钥加密
    public String encode(String code){
        String key = "";
        return encode(code,key);
    }

    //密钥加密
    public String encode(String code,String key){
        double k = 0;
        if(key.length() > 0) {
            char[] chars = encode(key).toCharArray();
            for (int i = 0; i < chars.length; i++) {
                k += (double)((int) chars[i])/100;
            }
        }
        int k1 = (int) k;
        return encode(code,k1);
    }

    public String decode(String code){
        String key = "";
        return decode(code,key);
    }

    //密钥加密
    public String decode(String code,String key){
        double k = 0;
        if(key.length() > 0) {
            char[] chars = encode(key).toCharArray();
            for (int i = 0; i < chars.length; i++) {
                k += (double)((int) chars[i])/100;
            }
        }
        int k1 = (int) k;
        return decode(code,k1);
    }

    private static String decode(String code,int k){
        char[] chars = code.toCharArray();
        int[] ints = new int[chars.length];
        for (int i = 0; i < chars.length; i++) {
            char c = chars[i];
            ints[i] = (int) c;
        }
        int v;
        //向左传播解密
        for (int i = 0; i < Math.sin(k) * 3 + 3; i++) {
            for (int j = ints.length - 1; j > 0; j--) {
                if (j % 2 == 0){
                    v = ints[j] - ints[j - 1] - k;
                    ints[j] = (v < MIN_CHARACTER) ? MAX_CHARACTER + 1 + v : v;
                }else {
                    v = ints[j] + ints[j - 1] + k;
                    ints[j] = (v > MAX_CHARACTER)?v - MAX_CHARACTER - 1: v;
                }
            }
            //第一项
            v = (ints.length == 1)?ints[0] - ROOT_VALUE - k:ints[0] - ints[ints.length - 1] - k;
            ints[0] = (v < MIN_CHARACTER) ? MAX_CHARACTER + 1 + v : v;
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (int anInt : ints) {
            stringBuilder.append((char) anInt);
        }
        return stringBuilder.toString();
    }

    private static String encode(String code,int k){
        String string = code;
        char[] chars = string.toCharArray();
        //用于存放ascii的数组
        int[] ints = new int[chars.length];
        for (int i = 0; i < chars.length; i++) {
            ints[i] = Integer.valueOf(chars[i]);
        }
        //向右传播加密
        for (int i = 0; i < Math.sin(k) * 3 + 3; i++) {
            int v;
            //第一项
            try {
                 v = (ints.length == 1)?ints[0] + ROOT_VALUE + k:ints[0] + ints[ints.length - 1] + k;
            }catch (ArrayIndexOutOfBoundsException e){
                return "";
            }
            ints[0] = (v > MAX_CHARACTER)?v - MAX_CHARACTER - 1 : v;
            for (int j = 1; j < ints.length; j++) {
                if (j % 2 == 0){
                    v = ints[j] + ints[j - 1] + k;
                    ints[j] = (v > MAX_CHARACTER)?v - MAX_CHARACTER - 1 : v;
                }else {
                    v = ints[j] - ints[j - 1] - k;
                    ints[j] = (v < MIN_CHARACTER)? MAX_CHARACTER + 1 + v : v;
                }
            }
        }

        StringBuilder stringBuilder = new StringBuilder();
        for (int anInt : ints) {
            stringBuilder.append((char) anInt);
        }
        return stringBuilder.toString();
    }

}
package com.wy.demo4;

import sun.nio.cs.UTF_32;

import java.util.Scanner;
import java.util.UUID;

public class Test2 {

    public static void main(String[] args) {

        String text = "牡蛎是真的好吃!!!为什么这么好吃因为牡蛎具有光滑的外表,鲜嫩的口感,看见了就让人垂延三尺,无法自拔!!!";

        //使用工具类
        StringUtils stringUtils = new AsciiEncodingStringUtils(text);

        //向下转型
        AsciiEncodingStringUtils asciiEncodingStringUtils = (AsciiEncodingStringUtils) stringUtils;

        long startTime=System.currentTimeMillis(); //获取开始时间
        String code = asciiEncodingStringUtils.encode(text,"os467");
        long endTime=System.currentTimeMillis(); //获取结束时间
        System.out.println("加密程序运行时间: "+(endTime-startTime)+"ms");
        System.out.println(code);

        startTime=System.currentTimeMillis(); //获取开始时间
        String deCode = asciiEncodingStringUtils.decode(code,"os467");
        endTime=System.currentTimeMillis(); //获取结束时间
        System.out.println("解密程序运行时间: "+(endTime-startTime)+"ms");

        System.out.println(deCode);

    }

}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 1300452403@qq.com

文章标题:Ascii码加密编码

字数:2.2k

本文作者:Os467

发布时间:2022-12-01, 15:02:11

最后更新:2022-12-01, 15:03:28

原始链接:https://os467.github.io/2022/12/01/Ascii%E7%BC%96%E7%A0%81%E5%8A%A0%E5%AF%86/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

×

喜欢就点赞,疼爱就打赏