上次我们说了一个MD5加密,我们来复习一下。这是一种单向加密方式。我们只能让拦截我们数据的人不知道我们真实的内容是什么,但是我们不能反向解密。一般用于信息验证的场合。今天说的就是一个可以加密也可以解密的东东,那就是RSA加密。
RSA加密后的内容是一个byte数组,解密需要的内容也是byte数组。但加密后的byte数组如果你尝试转为字符串你会发现是乱码。所以我们传输或者保存的时候需要直接对byte数组进行传输处理,不要尝试转为字符串,否则会有意想不到的错误。
代码如下,大家参考。依赖包我已经上传到资源了。
加密工具类RSAUtil.java
public class RSAUtil {
private static final String TAG = "RSAUtil";
private static final String Algorithm = "RSA";
public static KeyPair generateKeyPair() throws Exception {
try {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(Algorithm,
new org.bouncycastle.jce.provider.BouncyCastleProvider());
// 这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会降低
final int KEY_SIZE = 1024;
keyPairGen.initialize(KEY_SIZE, new SecureRandom());
KeyPair keyPair = keyPairGen.generateKeyPair();
return keyPair;
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}
//加密
public static byte[] encrypt(PublicKey pk, byte[] data) throws Exception {
try {
Cipher cipher = Cipher.getInstance(Algorithm,
new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(Cipher.ENCRYPT_MODE, pk);
int blockSize = cipher.getBlockSize();
int outputSize = cipher.getOutputSize(data.length);
int leavedSize = data.length % blockSize;
int blocksSize = leavedSize != 0 ? data.length / blockSize + 1
: data.length / blockSize;
byte[] raw = new byte[outputSize * blocksSize];
int i = 0;
while (data.length - i * blockSize > 0) {
if (data.length - i * blockSize > blockSize) {
cipher.doFinal(data, i * blockSize, blockSize, raw, i * outputSize);
} else {
cipher.doFinal(data, i * blockSize, data.length - i * blockSize, raw, i * outputSize);
}
i++;
}
return raw;
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}
//解密
public static byte[] decrypt(PrivateKey pk, byte[] raw) throws Exception {
try {
Cipher cipher = Cipher.getInstance(Algorithm,
new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(cipher.DECRYPT_MODE, pk);
int blockSize = cipher.getBlockSize();
ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
int j = 0;
while (raw.length - j * blockSize > 0) {
bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
j++;
}
return bout.toByteArray();
} catch (Exception e) {
throw new Exception(e.getMessage());
}
}
}
布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp">
<EditText
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入文字"/>
<Button
android:id="@+id/bt_jiam"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="加密"/>
<Button
android:id="@+id/bt_jiem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="解密"/>
<Button
android:id="@+id/bt_scmyd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="生成密钥对"/>
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private EditText et;
private Button bt_jiam;
private Button bt_jiem;
private Button bt_scmyd;
private KeyPair keyPair;//公钥私钥对
private byte[] bytes;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et = findViewById(R.id.et);
bt_jiam = findViewById(R.id.bt_jiam);
bt_jiem = findViewById(R.id.bt_jiem);
bt_scmyd = findViewById(R.id.bt_scmyd);
bt_jiam.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String content = et.getText().toString();
try {
bytes = RSAUtil.encrypt(keyPair.getPublic(),content.getBytes());
et.setText("");
} catch (Exception e) {
e.printStackTrace();
}
}
});
bt_jiem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
bytes = RSAUtil.decrypt(keyPair.getPrivate(),bytes);
et.setText(new String(bytes));
} catch (Exception e) {
e.printStackTrace();
}
}
});
bt_scmyd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
keyPair = RSAUtil.generateKeyPair();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
操作的时候我们要首先生成密钥对。接着就可以进行加解密操作。生成密钥对的操作可以放在服务端进行。然后将序列化的内容打包到我们本地端,并序列化成文件打包到apk中。