浅谈app中的密码学


Android基础

把java学好因为好多apk是java写的,不然反编译出来的代码都看不懂。把c学好,要不然同样so层看不懂。把linux学好,因为Android系统是基于linux开发的,好多命令都是相通的

推荐大家准备一个谷歌的那个pixel1代手机做测试用。不贵淘宝咸鱼一两百。

安卓开发idea:Android Studio(可以类比其他语言idea的使用方法)

Android Studio直接百度官网下载即可,Android Studio内置Android模拟器,可将开发的apk文件直接部署在内置的模拟卷上进行执行。所谓开发执行一条龙,来个界面:

在这里插入图片描述

Android Studio安装时会安装sdk目录,sdk目录很大,建议安
装在别的盘,在sdk目录下的platform-tools目录,会有一些命令,比如adb命令(可以连接到安卓手机的shell),fastboot(用来做真机刷机的)等,建议将此目录添加到环境变量,要不然使用这些命令工具的时候就要翻到这个目录进行执行:
在这里插入图片描述

用Android Studio开发的app项目下同样在src/main/java的代码为主执行代码

项目中一个名为AndroidMainfest.xml文件是一个清单文件,在这个文件里面我们可以知道包名,申请了哪些权限比如什么摄像头文件,录音权限之类的,在这里都可以看到

项目中res目录是一个资源目录,里面可能存了图标,颜色相关,logo,布局什么的

gradle是Android Studio下的一个包管理工具,有点类似maven,很好用

投屏利器:QtScrcpy

此工具可以将我们用数据线连接到电脑的手机,进行投屏,执行命令等操作,来个界面,我这里投出来的是Android Studio里的那个模拟的安卓手机(新买的测试机让我不小心从三楼摔下去了):

在这里插入图片描述

反编译工具:jadx

当我们拿到一个apk文件的时候,可以将他改成zip后缀的文件,进行解压,里面

基础部分未完待更。。。。

安卓中的密码学

我们为什么要学安卓中的密码学呢,其实加密方式大多都是通用的,但是安卓中实现加密的类和我们在java中调用的api加密类可能是不同的,我们要知道安卓进行加密时调用的包和类,这样我们在hook时才会更快,下面将会简单讲解安卓开发时调用的加密包

hex编码

  • Hex编码的原理

就是将原来8位的二进制字节打断,分成两个4位的,并且在前面加上4个零,
进行补位这样一个8位二进制字节就变成了2个8位的二进制字节,在将新得到的2个二进制字符进行16位进制转换
得到的新的16位字符串就是Hex的值,所以 二进制的[72, 69, 88] 《hex》 484558是相等的。
[72, 69, 88]byte数组的二进制=‭01001000‬ ‭01000101‬ ‭01011000‬
二进制=‭01001000‬ ‭01000101‬ ‭01011000‬ 进行hex的打断操作 ‭0100 1000‬ ‭0100 0101‬ ‭0101 1000
在加上前面的4个零得到一个新的6个8位二进制 = 0000‭0100 00001000 ‬0000‭0100 00000101‬ 0000‭0101 00001000
新的6个8位二进制 进行16进制转换 0000‭0100 00001000 ‬0000‭0100 00000101‬ 0000‭0101 00001000 = 484558
总结所以说Hex编码后的二进制长度变为了原来的2倍,所以字节长度增加了一倍。

例子:

字符串: HEX
ASCII码: [72,69,88]
二进制码: ‭01001000‬ ‭01000101‬ ‭01011000‬
重新分组: 0100 1000 0100 0101 0101 1000
高位补零后的二进制码: 00000100 00001000 00000100 00000101 00000101 00001000
十六进制码: 4 8 4 5 5 8
Hex码: 484558

如果我们更改16进制的码表,那么相应的我们从上图中的十六进制到hex码处就会发生转变

代码实现

import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;

import java.nio.charset.StandardCharsets;

public class Hex {

    @SuppressWarnings({"all"})
    public static void main(String[] args) throws Exception{
            String name = "wa1ki0g";
            byte[] bytes = name.getBytes(StandardCharsets.UTF_8);
            String encode = HexBin.encode(bytes);
            System.out.println(encode);
    }
}
//输出7761316B693067

上面是用我们java实现的,在安卓开发中,并没有自带的api,如果我们想在安卓开发中使用hex编码,需要用gradle导入外部的包:
在这里插入图片描述
安卓java层实现代码:

package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;

import java.nio.charset.StandardCharsets;

import okio.ByteString;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d("wa1ki0g","Testwa1ki0g");
        System.out.println(ByteString.of("wa1ki0g".getBytes()).hex());
    }
}

在这里插入图片描述
调用的包:okio.ByteString.hex

url编码

url编码就是上面的hex编码后,每两位补一个百分号,比如wa1ki0g hex后是7761316B693067,那么url编码就是:

在这里插入图片描述
base64编码
base64编码的原理

标准 Base64 里的 64 个可打印字符是 A-Za-z0-9+/,分别依次对应索引值 0-63。举个例子,c在ascii的码表中是99,二进制是01100011,bash64是以六位来对应码表中的一个值,所以就会在01100011后补充四个0,就会变为011000 110000,转成十进制分别为24,48,在base64中的码表为YW,base64后的字符长度规定最后要是4的倍数,所以最后会补充两个等于号为Yw==:
在这里插入图片描述
在这里插入图片描述
java代码实现:

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class base64 {
    public static void main(String[] args) {
        System.out.println(Base64.getEncoder().encodeToString("c".getBytes(StandardCharsets.UTF_8)));
    }
}
//输出Yw==

安卓实现:安卓实现有两种方式,1种就是上面那个自己导入的okhttp3包,他最终调用的是okio.base64,另外一种就是自带的android.util.base64

安卓java层代码:

package com.example.myapplication;

import androidx.appcompat.app.AppCompatActivity;


import android.os.Bundle;

import java.util.Base64;


public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        String s = Base64.getEncoder().encodeToString("c".getBytes());
        byte[] code = Base64.getEncoder().encode("c".getBytes());
        System.out.println(s);
        System.out.println(new String(code));
        String s2 = android.util.Base64.encodeToString("c".getBytes(),0);
        System.out.println("hhhh:"+s2);


    }


}

输出:
在这里插入图片描述

消息摘要算法

算法特点:

  1. 消息摘要算法/单向散列函数/哈希函数
  2. 不同长度的输入,产生固定长度的输出
  3. 散列后的秘文不可逆
  4. 散列后的结果唯一(不够准确但是一般这么说)
  5. 哈希碰撞(指的就是密文由于位数是固定的,就会造成数量是有限的,而我们的明文是无限的就有可能造成,两个不同的明文,加密后的密文是一样的)
  6. 一般用于校验数据完整性,签名sign
  7. 由于密文不可逆,所以服务端也无法解密,想要验证,就需要跟前端一样的方式去重新签名一遍。
  8. 签名算法一般会把源数据和签名后的值一起提交到服务端,在现实中我们要保证在签名时候的源数据和提交上去的源数据一致
  9. 常见算法:md5,sha1,sha256,sha512,HmacMD5,HmacSHA256,HmacSHA512,RiPEMD160,HmacRIPEMD160,PBKDF2,EvpKDF

md5算法

安卓java层md5加密:

package com.example.myapplication;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import okio.ByteString;

public class MD5 {
    public String getMd5(String s) throws NoSuchAlgorithmException {
       MessageDigest md5 =  MessageDigest.getInstance("MD5");

       byte[] bytes =  md5.digest(s.getBytes());

       ByteString byteString = ByteString.of(bytes);
       String m = byteString.hex();
       System.out.println("md5:"+m);
       return "";
    }
}

运行结果:
在这里插入图片描述
我们可通过MessageDigest.update方法对明文数据进行分段传输,防止我们直接传了一个大文件进行加密而造成程序bug,MessageDigest.reset方法可对我们update进去的分段数据进行清空

  1. 在代码中,messageDigest.digest(); 计算md5值之前,即使我们并没有传入任何参数,也可以产生md5值,我们可以用这种方法,来判断加密
  2. 碰到加salt的md5,可以直接输入空值,得到md5去cmd查下,有可能得到salt
  3. 调用的包 java.security.MessageDigest

sha算法

sha算法同样是一种消息摘要算法,调用的包与md5一样: java.security.MessageDigest

安卓java层代码:

package com.example.myapplication;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import okio.ByteString;

public class SHA {
    public String getSHA(String s) throws NoSuchAlgorithmException{
        MessageDigest sha = MessageDigest.getInstance("SHA-1");
        byte[] d = sha.digest(s.getBytes());
        ByteString byteString = ByteString.of(d);
        String m = byteString.hex();
        System.out.println("sha1:"+m);
        return "";

    }
}

运行结果:

在这里插入图片描述
在这里插入图片描述

MAC算法

  1. mac算法与md5和sha的算法大致相同,与他们的区别就是多了个密钥,密钥可以随便给的
  2. 生成密钥使用的包:javax.crypto.spec.SecretKeySpec;
  3. 进行加密使用的包:javax.crypto.Mac;

安卓java层代码实现:

package com.example.myapplication;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import okio.ByteString;

public class MAC {
    public String getMAC(String s) throws NoSuchAlgorithmException, InvalidKeyException {
      SecretKeySpec secretKeySpec =  new SecretKeySpec("key".getBytes(),"HmacMD5");
      String key = new String(secretKeySpec.getEncoded());
      System.out.println("密钥为:"+key);
      Mac hmacmd5 = Mac.getInstance("HmacMD5");
      hmacmd5.init(secretKeySpec);
      hmacmd5.update(s.getBytes());
      byte[] bytes = hmacmd5.doFinal();
      ByteString byteString = ByteString.of(bytes);
      String h = byteString.hex();
      System.out.println("密文为:"+h);

      return "";

    }
}

运行结果:
在这里插入图片描述
在这里插入图片描述

对称加密算法

对称加密算法的特点:
.

  1. 加密/解密的过程可逆的算法叫做加密算法,加密/解密使用相同的密钥,叫做对称加密算法
  2. 对称加密算法的密钥可以随机给,但是有位数要求
  3. 对称加密算法的输入数据没有长度要求,加密速度快
  4. 各算法的长度:RC4密钥长度为1-256字节,DES密钥长度为8字节,3DES/DESede/TripleDES密钥长度为16,AES 密钥长度为16,24,32字节,根据密钥长度不同AES又分为AES-128,AES-192,AES-256
  5. RC4加密在安卓java层没有可以直接调用的api,如果想要用的话就要自己进行实现,所以在实战中可能见到的会稍微少一点
  6. 在rsa中填充方式为NoPadding时会对明文进行填充的。但是在对称加密算法中,填充方式为NoPadding时,是不会进行填充的,此时加密的密文必须刚好等于分组长度倍数,否则报错,如果使用PKCS5Padding,则会对加密的密文填充1字节-1个分组的长度
  7. 没有指明加密方式和填充方式时,表示使用默认的AES/ECB/PKCS5Padding

对称加密分类:

  1. 序列加密/流加密:以字节流的方式,依次加密(解密)明文(密文)中的每一个字节如RC4
  2. 分组加密:将明文消息进行分组(每组有多个字节),逐组进行加密如DES,3DES,AES
  3. 加密模式: CryptoJS这个js加密库会提供ECB,CBC,CFB,OFB,CTR五种模式,其中最常用的是ECB,CBC
  4. 填充方式:CryptoJS提供NoPadding,Pkcs7(Pkcs5),ZeroPadding,Iso10126,Iso97971,AnsiX923,在java中比较常用的是NoPadding,Pkcs7(Pkcs5)

Des加密

  1. 没有指明加密模式和填充方式,表示使用默认的
  2. 加密后的字节数组同消息摘要算法一样要进行hex,base等编码要不然可能会出现乱码
  3. DES算法明文按照64位进行加密
  4. 要复现一个对称加密算法需要得到以下几个东西:明文,key,iv,mode,padding
  5. 明文,key,iv需要注意解析方式,而且不一定要是字符串形式
  6. 如果加密模式是ecb,则不需要iv
  7. 如果明文中有两个分组的内容相同,这两个部分ecb模式会得到完全一样的密文,cbc不会,原理在下
  8. 加密算法的结果通常与明文等长或者更长,如果变短了可能是gzip,protobuf

我这里调用的是javax.crypto.spec.SecretKeySpec;来生成密钥对象,使用javax.crypto.Cipher;来进行加密,正常des的加密生成密钥用的是javax.crypto.spec.DESKeySpec;,我这里用的是javax.crypto.spec.SecretKeySpec,因为DESKeySpec最终调用的是SecretKeySpec。所以我们在hook的时候有时候他调用SecretKeySpec去完成,我们hook SecretKeySpec也可以

ecb模式与cbc模式的区别:
举个例子假如我们现在有明文:”admin123admin123admin123admin”
那么他会八个字节分组然后进行填充 :”admin123 admin123 admin123 admin+填充”
这里说的填充方式就是代码中的这里:
在这里插入图片描述
填充完毕后ecb模式会对各个分组进行加密,各个分组互相不干扰,如果是cbc模式有了iv向量,此时就不同了,我们第一组的明文会跟我们的iv向量进行异或后在进行加密,然后第一组的密文会和第二组的明文进行异或出第二组的密文,然后依次递归,在我们的cbc模式中密文是受iv向量影响的,我们的每一个分组的密文都会受上一个分组影响

安卓java层代码,ecb模式;

package com.example.myapplication;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

import okio.ByteString;

public class DES {
    public String getDES(String s) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
        SecretKeySpec secretKeySpec =  new SecretKeySpec("12345678".getBytes(),"DES");
        String key = new String(secretKeySpec.getEncoded());
        System.out.println("密钥为:"+key);

        Cipher des = Cipher.getInstance("DES/ECB/PKCS7Padding");
        des.init(Cipher.ENCRYPT_MODE,secretKeySpec);
        byte[] bytes=des.doFinal(s.getBytes());
        ByteString byteString = ByteString.of(bytes);
        String hex = byteString.hex();
        System.out.println("密文为:"+hex);
        String base = byteString.base64();
        System.out.println("密文为:"+base);

        return "";

    }
}

运行结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
cbc模式,要加iv:

package com.example.myapplication;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import okio.ByteString;

public class DES {
    public String getDES(String s) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
        SecretKeySpec secretKeySpec =  new SecretKeySpec("12345678".getBytes(),"DES");
        String key = new String(secretKeySpec.getEncoded());
        System.out.println("密钥为:"+key);
        IvParameterSpec iv =new IvParameterSpec("12345678".getBytes());

        Cipher des = Cipher.getInstance("DES/CBC/PKCS5Padding");
        des.init(Cipher.ENCRYPT_MODE,secretKeySpec,iv);
        byte[] bytes=des.doFinal(s.getBytes());
        ByteString byteString = ByteString.of(bytes);
        String hex = byteString.hex();
        System.out.println("密文为:"+hex);
        String base = byteString.base64();
        System.out.println("密文为:"+base);

        return "";

    }
}

运行结果:
在这里插入图片描述
在这里插入图片描述

DESede算法(又名Triple DES,3DES)

跟上面的DES还是比较像的,密钥长度与DES不同,是他的3倍,密文长度也会长一点。同上这里调用的是javax.crypto.spec.SecretKeySpec;来生成密钥对象,使用javax.crypto.Cipher;来进行加密,正常DESded的加密生成密钥用的是javax.crypto.spec.DESedeKeySpec;,我这里用的是javax.crypto.spec.SecretKeySpec,因为DESedeKeySpec最终调用的是SecretKeySpec。所以我们在hook的时候有时候他调用SecretKeySpec去完成,我们hook SecretKeySpec也可以

我这里只进行ecb模式的演示,cbc模式下的可类比上面:
安卓java层代码:

package com.example.myapplication;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

import okio.ByteString;

public class DESede {
    public String getDESede(String s) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
        SecretKeySpec secretKeySpec =  new SecretKeySpec("123456781234567812345678".getBytes(),"DESede");
        String key = new String(secretKeySpec.getEncoded());
        System.out.println("密钥为:"+key);

        Cipher dessade = Cipher.getInstance("DESede/ECB/PKCS5Padding");
        dessade.init(Cipher.ENCRYPT_MODE,secretKeySpec);
        byte[] bytes=dessade.doFinal(s.getBytes());
        ByteString byteString = ByteString.of(bytes);
        String hex = byteString.hex();
        System.out.println("密文为:"+hex);
        String base = byteString.base64();
        System.out.println("密文为:"+base);

        return "";

    }
}

结果:
在这里插入图片描述
在这里插入图片描述

AES算法

  1. AES算法根据密钥长度与加密轮数的不同,可以分为AES128,AES192,AES256,密钥长度分别对应16个字节,24个字节,32个字节
  2. 工作模式最常用的是ecb与cbc,与上面的des比较类似
  3. 填充方式最常用的是NoPadding,PKCS5Padding,与des也比较像
  4. 分组长度为16个字节

使用javax.crypto.spec.SecretKeySpec;来生成密钥,使用javax.crypto.Cipher;来进行处理加密。CBC的代码实现与上面的都比较类似,同样这里只演示ECB模式,安卓java层代码:

package com.example.myapplication;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

import okio.ByteString;

public class AES {
    public String getAes(String s) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
        SecretKeySpec secretKeySpec =  new SecretKeySpec("1234567812345678".getBytes(),"AES");
        String key = new String(secretKeySpec.getEncoded());
        System.out.println("密钥为:"+key);

        Cipher aes1 = Cipher.getInstance("AES/ECB/PKCS5Padding");
        aes1.init(Cipher.ENCRYPT_MODE,secretKeySpec);
        byte[] bytes=aes1.doFinal(s.getBytes());
        ByteString byteString = ByteString.of(bytes);
        String hex = byteString.hex();
        System.out.println("密文为:"+hex);
        String base = byteString.base64();
        System.out.println("密文为:"+base);

        return "";

    }
}

结果:
在这里插入图片描述
在这里插入图片描述

非对称加密算法

典型算法:RSA

  1. 需要生成一个密钥对,包含公钥与私钥,密钥不是随便写的,密钥对生成网址:http://web.chacuo.net/netrsakeypair
  2. 公钥加密的数据,私钥才能解密。私钥加密的数据,公钥才能解密。
  3. 一般公钥是公开的,私钥保密,从公钥无法推导出私钥
  4. 加密处理安全,但是性能极差,单次加密长度有限制
  5. RSA算法既可用于加密解密,也可用于数据签名

RSA算法

  1. 密钥长度的范围在512~65536位,但必须是64的倍数
  2. 工作模式有ECB与NONE但种经过测试,两种工作模式生成的密文是一样的
  3. RSA也是分组加密的
  4. 填充方式常用的是Nopadding与PKCS1Padding
  5. 私钥的格式:有两种,pkcs1与pkcs8,pkcs1的开头通常是—–BEGIN RSA PRIVATE KEY—–,pkcs8的开头通常是—–BEGIN PRIVATE KEY—–,java中的私钥必须是pkcs8格式
  6. 使用PKCS1Padding填充方式时,明文最大字节数为密钥字节数-11,得到的密文密钥等长
  7. 使用Nopadding填充方式时,明文最大字节数为密钥字节数,得到的密文密钥等长
  8. 判断填充方式:在RSA中使用Nopadding填充方式,每次的加密结果是不会变的,使用PKCS1Padding进行填充时每次的填充都是不一样的,每次的加密结果可能都不是一样的
  9. 没有指明加密方式和填充方式,默认使用 RSA/ECB/Nopadding

安卓java层中,解析公钥用的包:java.security.spec.X509EncodedKeySpec; 解析密钥用的包:java.security.spec.PKCS8EncodedKeySpec; 进行加密解密的包:javax.crypto.Cipher;
。下面的例子是RSA/ECB/PKCS1Padding模式下的,在RSA/ECB/PKCS1Padding与RSA/NONE/PKCS1Padding加密出的结果是一样的。在RSA中使用Nopadding填充方式也会进行填充的,填充的是字节0,所以我们每次的加密结果是不会变的,但是当我们使用PKCS1Padding进行填充时,因为有填充的原因所以每次的加密结果可能都不是一样的。其余的大致原理相同就不进行演示,只对下面这种运用RSA/ECB/PKCS1Padding的进行演示。

下面是实现的对RSA公钥私钥的解析,并通过公钥进行加密,通过私钥进行解密的一个过程:

package com.example.myapplication;

import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import okio.ByteString;

public class RSA_B{
    public PublicKey pky(String pkey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] bytes = ByteString.decodeBase64(pkey).toByteArray();
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(bytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        return  publicKey;
    }
    public PrivateKey sky(String skey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] bytes = ByteString.decodeBase64(skey).toByteArray();
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(bytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        return  privateKey;
    }

    public String encPky(String s) throws Exception{
        PublicKey publicKey = pky("MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDiT4I2+IXUaUHRm/y9J0vVwuW5\n" +
                "JgyVRk5VnCxq5OJiEUyQQYqGJcfr0ryvOEDqurB8sWIDWpHdV4h42Va+gqhVb+1D\n" +
                "S6+nd+1gJeRC39ZDHcnwQ4ihJUalregndEZKG31PBFS2ZLahbj6vNWgHwO5mQ2H2\n" +
                "ztguZYKi2Bf/HNUPvQIDAQAB");
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE,publicKey);
        byte[] bytes = cipher.doFinal(s.getBytes());

        ByteString byteString = ByteString.of(bytes);
        String base = byteString.base64();
        String hex = byteString.hex();
        System.out.println("明文为:"+s);
        System.out.println("密文:"+base+"\n密文:"+hex);
        return "密文:"+base+"\n密文:"+hex;

    }

    public String dencPky(String s) throws Exception{
        PrivateKey privateKey = sky("MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOJPgjb4hdRpQdGb\n" +
                "/L0nS9XC5bkmDJVGTlWcLGrk4mIRTJBBioYlx+vSvK84QOq6sHyxYgNakd1XiHjZ\n" +
                "Vr6CqFVv7UNLr6d37WAl5ELf1kMdyfBDiKElRqWt6Cd0RkobfU8EVLZktqFuPq81\n" +
                "aAfA7mZDYfbO2C5lgqLYF/8c1Q+9AgMBAAECgYB67tW9JqMMD2FBi4pu9bmsFILV\n" +
                "YGXVcKt8takrJ8oRm3QLqI6m8D75SzBTvisFVwQnt/OV/szdf38Spn0IX9EwEl4x\n" +
                "4ZzKLYiop3R9dMGMzWUfzrGsiDp3h1goGnEdKvjFGvLR+1bch9bnR9Y1ReyEheah\n" +
                "rkaKisKvDOYlJodEAQJBAPW/oeFFoVPBRgeoGuA9U68LdEnx4yopAn9DN1MVxsiF\n" +
                "tZPlwgVbyHYltED9agui1Gxx0VXK32PKy1/fYWOzHbECQQDrwEvuKbzkLj5cJ978\n" +
                "f38lNZZpEU+vlq2jqJ+vyvqM6a1RMjocGTV7z+0KwWOh8+/St0ENEfZncp9TQDHw\n" +
                "gBnNAkEAgoh+uQTeU3m28/w0AmYw3CrOYzSrwEo2PFj8uxI3G24CbAO/kk8VZMRU\n" +
                "Qa0ZtgKQqOWwFs0C6aPfcRZbSbTrkQJANHRm8KkMxGCds3eTn+7mZWsU+m/FoTYP\n" +
                "kJiWX1D0iqH71FMups3dHp1XCsuY1ZInTGVF7hiPENlqJeXktrRqCQJBAN6WiJe9\n" +
                "QIkWlqPbN57Xo8+djiwlk8pX4xTj4ZuBf2b9BihREWHabutJ4giawHNlUAi1p7iZ\n" +
                "WO7papf2RkpkQ0I=");

        byte[] byte1 = ByteString.decodeBase64(s).toByteArray();
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE,privateKey);
        byte[] bytes = cipher.doFinal(byte1);
        System.out.println("明文为:"+new String(bytes));

        return "";

    }
}

结果:
在这里插入图片描述


文章作者: wa1ki0g
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 wa1ki0g !
  目录