MD5加密,判断文件是否被篡改,解码与编码,16进制与2进制的转换
加密算法:步骤
1 用每个byte去和11111111做与运算并且得到的是int类型的值:
byte & 11111111;
2、把int 类型转成 16进制并返回String类型;
3、不满八个二进制位就补全;
public static void main(String[] args) throws NoSuchAlgorithmException {
//得到一个信息摘要器
MessageDigest digest = MessageDigest.getInstance("md5");
String password = "123456";//密码
byte [] result = digest.digest(password.getBytes());//这里也可以传读取的一个文件的字节数组
StringBuffer buffer = new StringBuffer();
//把每一个 字节 & 0xff
for(byte b : result){
int nuber = b & 0xff;
String str = Integer.toHexString(nuber);//转换为16进制的字符串
if(str.length()==1){
buffer.append("0");//如果该字符串只有一位数就在前面补0
}
buffer.append(str);
}
//这就是MD5加密得到的值,如果想更难破解可以拿这个值再加密
System.out.println(buffer);
}
与保存的加密密码判断是否一致时,将用户输入的密码加密再比较就是
网站在线验证算法是否正确 www.cmd5.com
还可以校验文件的md5 sha1签名.
上面代码中也可以读取一个文件,然后将读取出来的字符串转换成字节数组,然后通过 byte [] result = digest.digest("字节数组");方法......获取这个文件的MD5码,文件名修改了MD5码是不会变的,但是如果文件的内容变化了.得到的MD5码就不同了(加了空格都会不同)
这也是判断文件是否被别人篡改的标示
/** * 获取文件的MD5值,path为文件的全路径 * 获取文件的特征信息 */ public String getFileMD5(String path){ try { File file=new File(path); FileInputStream fis=new FileInputStream(file); byte[] byffer = new byte[1024]; int len=-1; MessageDigest digest = MessageDigest.getInstance("md5"); while((len=fis.read(byffer))!=-1){ digest.update(byffer,0,len); } byte[] result=digest.digest(); StringBuffer sb=new StringBuffer(); for (byte b : result) { int number=b & 0xff;//加盐 String str = Integer.toHexString(number); if(str.length() == 1){ sb.append("0"); } sb.append(str); } return sb.toString(); } catch (Exception e) { e.printStackTrace(); } return null; }
1.编码和解码
1.编码的概念
用一种统一的公认的规则来将数据进行统一的编排。(1对1)
如ascall编码中
A ---- 65
编码的方式:
1.BASE64(A-Z,a-z,0-9,+,/)
2.URL编码
base64编码与解码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.util.Base64; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; public class Base64Activity extends AppCompatActivity { private EditText mEditText; private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_base64); initView(); } private void initView() { mEditText = (EditText) findViewById(R.id.et_base64_input); mTextView = (TextView) findViewById(R.id.tv_base64_show); } public void onClick(View view) { if (view!=null){ switch (view.getId()){ case R.id.bt_base64_encode: // 获取输入框的内容 String content = mEditText.getText().toString().trim(); // 判空 if (TextUtils.isEmpty(content)){ Toast.makeText(Base64Activity.this, "您还没有输入需要编码的内容", Toast.LENGTH_SHORT).show(); return; } // 编码 byte[] encode = Base64.encode(content.getBytes(), Base64.DEFAULT); // 设置到控件上 mTextView.setText(new String(encode)); break; case R.id.bt_base64_decode: // 获取TextView上已经编码的内容 String decodeString = mTextView.getText().toString().trim(); // 判空 if (TextUtils.isEmpty(decodeString)){ Toast.makeText(Base64Activity.this, "您还没有编码过", Toast.LENGTH_SHORT).show(); return; } // 解码 byte[] decode = Base64.decode(decodeString.getBytes(), Base64.DEFAULT); // 把结果再设置到TextView上。 mTextView.setText(new String(decode)); break; default: break; } } } }
Url编码与解码,好多网址就是使用这种编码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; public class UrlActivity extends AppCompatActivity { private EditText mEditText; private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_url); initView(); // UrlEncode URLDecode 一般使用在服务器和客户端 传递中文参数的时候,一般会把参数通过UrlEncode 防止客户端 // 传递过来的中文参数出现乱码的情况 } private void initView() { mEditText = (EditText) findViewById(R.id.et_url_input); mTextView = (TextView) findViewById(R.id.tv_url_show); } public void onClick(View view) { if (view!=null){ switch (view.getId()){ case R.id.bt_url_encode: String content = mEditText.getText().toString().trim(); if (TextUtils.isEmpty(content)){ Toast.makeText(UrlActivity.this, "您还没有输入任何需要编码的内容", Toast.LENGTH_SHORT).show(); return; } try { String encode = URLEncoder.encode(content, "UTF-8"); mTextView.setText(encode); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } break; case R.id.bt_url_decode: String decodeContent = mTextView.getText().toString().trim(); if (TextUtils.isEmpty(decodeContent)){ Toast.makeText(UrlActivity.this, "您还没有进行过编码", Toast.LENGTH_SHORT).show(); return; } try { String decode = URLDecoder.decode(decodeContent, "UTF-8"); mTextView.setText(decode); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } break; default: break; } } } }
2.加密和解密
1.对称加密(DES-->3DES-->AES)
概念:加密和解密用的是同一个密钥
特点:强度较低,只要丢失加密或者解密用到的密钥,那么信息就会出现安全隐患
2.非对称加密(RSA)
概念:加密和解密用的不同的密钥
特点:密码强度较高
3.信息摘要(MD5,SHA)
概念:用它来做验证数据的完整性的。
对称加密与解密:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.util.Base64; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; 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; public class DesActivity extends AppCompatActivity { private EditText mEditTextPassword; private EditText mEditTextContent; private TextView mTextViewResult; private TextView mTextViewDecode; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_des); initView(); // DES 加密解密密码的长度必须是八位(8 个byte) } private void initView() { mEditTextContent = (EditText) findViewById(R.id.et_des_content); mEditTextPassword = (EditText) findViewById(R.id.et_des_password); mTextViewDecode = (TextView) findViewById(R.id.tv_des_decode); mTextViewResult = (TextView) findViewById(R.id.tv_des_result); } public void onClick(View view) { if (view!=null){ switch (view.getId()){ case R.id.bt_des_encode: // 获取控件上的值 // DES 加密解密密码的长度必须是八位(8 个byte) String password = mEditTextPassword.getText().toString().trim(); String content = mEditTextContent.getText().toString().trim(); //判空 if (TextUtils.isEmpty(password)||TextUtils.isEmpty(content)){ Toast.makeText(DesActivity.this, "请完善信息", Toast.LENGTH_SHORT).show(); return; } // 加密 // 初始化加密引擎 try { Cipher cipher = Cipher.getInstance("DES"); //初始化加密的key SecretKeySpec spec = new SecretKeySpec(password.getBytes(),"DES"); // 初始化加密引擎 cipher.init(Cipher.ENCRYPT_MODE,spec); // 加密 byte[] bytes = cipher.doFinal(content.getBytes()); // 经过base64处理 Log.d("TAG", "onClick: bytes == "+new String(bytes)); byte[] encode = Base64.encode(bytes, Base64.DEFAULT); // 设置给控件 mTextViewResult.setText(new String(encode)); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } //设置值到控件上 break; case R.id.bt_des_decode: String result = mTextViewResult.getText().toString().trim(); String passwordes = mEditTextPassword.getText().toString().trim(); if (TextUtils.isEmpty(result)||TextUtils.isEmpty(passwordes)){ Toast.makeText(DesActivity.this, "请完善信息", Toast.LENGTH_SHORT).show(); return; } try { // 初始化加密引擎 Cipher cipher = Cipher.getInstance("DES"); // 初始化key // DES 加密解密密码的长度必须是八位(8 个byte) SecretKeySpec keySpec = new SecretKeySpec(passwordes.getBytes(),"DES"); cipher.init(Cipher.DECRYPT_MODE, keySpec); // 因为在我们加密后 经过了Base64处理了(Encode) ,所以 加密必须经过base64处理回来(decode) byte[] bytes = result.getBytes(); byte[] decode = Base64.decode(bytes, Base64.DEFAULT); byte[] contentes = cipher.doFinal(decode); mTextViewDecode.setText(new String(contentes)); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } break; default: break; } } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.util.Base64; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; 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; public class AESActivity extends AppCompatActivity { private EditText mEditTextPassword; private EditText mEditTextContent; private TextView mTextViewDecode; private TextView mTextViewResult; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_aes); initView(); // 密码长度必须是16byte 或者24 或者32 一个字符两个字节 } private void initView() { mEditTextContent = (EditText) findViewById(R.id.et_aes_content); mEditTextPassword = (EditText) findViewById(R.id.et_aes_password); mTextViewResult = (TextView) findViewById(R.id.tv_aes_result); mTextViewDecode = (TextView) findViewById(R.id.tv_aes_decode); } public void onClick(View view) { try { if (view!=null){ switch (view.getId()){ case R.id.bt_aes_encode: // 获取控件值 String content = mEditTextContent.getText().toString().trim(); // 密码长度必须是16byte 或者24 或者32 String password= mEditTextPassword.getText().toString().trim(); //判空 if (TextUtils.isEmpty(content)||TextUtils.isEmpty(password)){ Toast.makeText(AESActivity.this, "请完善信息", Toast.LENGTH_SHORT).show(); return; } // 加密 Cipher cipher = Cipher.getInstance("AES"); SecretKeySpec key = new SecretKeySpec(password.getBytes(),"AES"); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] bytes = cipher.doFinal(content.getBytes()); byte[] encode = Base64.encode(bytes, Base64.DEFAULT); mTextViewResult.setText(new String(encode)); // 设置值到控件上 break; case R.id.bt_aes_decode: // 获取控件值 final String result = mTextViewResult.getText().toString().trim(); // 密码长度必须是16byte 或者24 或者32 final String passwordes = mEditTextPassword.getText().toString().trim(); //判空 if (TextUtils.isEmpty(result)||TextUtils.isEmpty(passwordes)){ Toast.makeText(AESActivity.this, "请完善内容", Toast.LENGTH_SHORT).show(); return; } // 解密 Cipher cipherTwo = Cipher.getInstance("AES"); SecretKeySpec keySpec = new SecretKeySpec(passwordes.getBytes(),"AES"); cipherTwo.init(Cipher.DECRYPT_MODE, keySpec); byte[] decode = Base64.decode(result.getBytes(), Base64.DEFAULT); final byte[] decodeResult = cipherTwo.doFinal(decode); mTextViewDecode.setText(new String(decodeResult)); // 设置值到控件上 break; default: break; } } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } } }
非对称:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import android.content.Context; import android.content.SharedPreferences; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.util.Base64; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; public class RSAActvitiy extends AppCompatActivity { private EditText mEditText; private TextView mTextViewResult; private TextView mTextViewDecode; private PrivateKey mPrivateKey; private PublicKey mPublicKey; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_rsaactvitiy); initView(); initData(); } private void initData() { try { // 初始化RSA密码对 KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); // 设置密码对的长度,随机生成的密码对,每次生成都不会相同 generator.initialize(1024); //生成密码对 KeyPair keyPair = generator.generateKeyPair(); //获取私钥 mPrivateKey = keyPair.getPrivate(); //获取公钥 mPublicKey = keyPair.getPublic(); // 把服务器的私钥存入共享参数 SharedPreferences sp = getSharedPreferences("1605", Context.MODE_PRIVATE); SharedPreferences.Editor edit = sp.edit(); // 获取私钥的byte数组 final byte[] privateKeyEncoded = mPrivateKey.getEncoded(); //因为我们要存起来,然后在读出来,所以得经过Base64处理 byte[] encodePrivate = Base64.encode(privateKeyEncoded, Base64.DEFAULT); edit.putString("privateKey",new String(encodePrivate)); edit.commit(); // 把 私钥和公钥转化成String byte[] encoded = mPublicKey.getEncoded(); byte[] encode = Base64.encode(encoded, Base64.DEFAULT); byte[] encodedp = mPrivateKey.getEncoded(); byte[] encodep = Base64.encode(encodedp, Base64.DEFAULT); Log.d("TAG", "initData: priateKey == "+new String(encode)+" publicKey == "+new String(encodep)); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } private void initView() { mEditText = (EditText) findViewById(R.id.et_rsa_content); mTextViewDecode = (TextView) findViewById(R.id.tv_rsa_decode); mTextViewResult = (TextView) findViewById(R.id.tv_rsa_result); } public void onClick(View view) { if (view!=null){ switch (view.getId()) { case R.id.bt_rsa_encode: // 获取需要加密的内容 String content = mEditText.getText().toString().trim(); //判空 if(TextUtils.isEmpty(content)){ Toast.makeText(RSAActvitiy.this, "请输入您要加密的内容", Toast.LENGTH_SHORT).show(); return; } // 初始化加密 try { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, mPublicKey); byte[] bytes = cipher.doFinal(content.getBytes()); byte[] encode = Base64.encode(bytes, Base64.DEFAULT); mTextViewResult.setText(new String(encode)); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } //设置数据 break; case R.id.bt_rsa_decode: try { String result = mTextViewResult.getText().toString().trim(); if (TextUtils.isEmpty(result)){ Toast.makeText(RSAActvitiy.this, "您还没有进行加密", Toast.LENGTH_SHORT).show(); return; } Cipher ciphers = Cipher.getInstance("RSA"); ciphers.init(Cipher.DECRYPT_MODE, mPrivateKey); byte[] decode = Base64.decode(result.getBytes(), Base64.DEFAULT); byte[] bytes = ciphers.doFinal(decode); mTextViewDecode.setText(new String(bytes)); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } break; case R.id.bt_rsa_sp: // 拿到sp里面私钥传话成的String final SharedPreferences sp = getSharedPreferences("1605", Context.MODE_PRIVATE); String privateKeyStr = sp.getString("privateKey", ""); if (TextUtils.isEmpty(privateKeyStr)){ Toast.makeText(RSAActvitiy.this, "您还没有存入私钥", Toast.LENGTH_SHORT).show(); return; } // 把String 传话成私钥 byte[] priKeyBytes = Base64.decode(privateKeyStr, Base64.DEFAULT); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(priKeyBytes); try { KeyFactory factory = KeyFactory.getInstance("RSA"); PrivateKey privateKey = factory.generatePrivate(keySpec); // 解密公钥加密后的内容 Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); String encodeContent = mTextViewResult.getText().toString().trim(); if (TextUtils.isEmpty(encodeContent)){ Toast.makeText(RSAActvitiy.this, "您还没有进行加密,请不要解密", Toast.LENGTH_SHORT).show(); return; } byte[] bytes = cipher.doFinal(Base64.decode(encodeContent, Base64.DEFAULT)); mTextViewDecode.setText(new String(bytes)); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeySpecException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } // 解密 break; default: break; } } } }
SHA:判断是否篡改
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class Sha1Activity extends AppCompatActivity { private EditText mEditText; private TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sha1); initView(); } private void initView() { mEditText = (EditText) findViewById(R.id.et_sha1_input); mTextView = (TextView) findViewById(R.id.tv_sha1_result); } //7c4a8d09ca3762af61e59520943dc26494f8941b //e10adc3949ba59abbe56e057f20f883e public void onClick(View view) { if (view!=null){ try { String content = mEditText.getText().toString().trim(); if (TextUtils.isEmpty(content)){ Toast.makeText(Sha1Activity.this, "请您输入您要摘要的内容", Toast.LENGTH_SHORT).show(); return; } MessageDigest digest = MessageDigest.getInstance("SHA1"); digest.update(content.getBytes()); final byte[] resultBytes = digest.digest(); StringBuffer buffer = new StringBuffer(); for (int i = 0; i < resultBytes.length; i++) { String index = Integer.toHexString(resultBytes[i] & 0xff); if (index.length()==1){ buffer.append("0"); } buffer.append(index); } Log.d("TAG", "onClick: " +buffer.toString()); mTextView.setText(buffer.toString()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } } }
字节转16进制字符串与16进制字符串转字节数组:
/** * 将二进制转换成16进制 * * @param buf * @return */ public static String parseByte2HexStr(byte buf[]) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < buf.length; i++) { String hex = Integer.toHexString(buf[i] & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } sb.append(hex.toUpperCase()); } return sb.toString(); } /** * 将16进制转换为二进制 * * @param hexStr * @return */ public static byte[] parseHexStr2Byte(String hexStr) { if (hexStr.length() < 1) return null; byte[] result = new byte[hexStr.length() / 2]; for (int i = 0; i < hexStr.length() / 2; i++) { int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); result[i] = (byte) (high * 16 + low); } return result; }
解密规则:
1.数据都用AES加密与解密(动态的,每次客户端生成)
2.将AES的秘钥使用RSA加密,然后提交给服务器
3.RSA的公钥与私钥由服务器生成(写死的,我们保存到代码中就行)
AES工具类如下:
import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; /** * AES的加密与解密 */ public class AESUtil { /** * AES加密字符串 * * @param content * 需要被加密的字符串 * @param key * 秘钥 * @return 密文 */ public static byte[] encrypt(String content, byte[] key) { try { Cipher cipher = Cipher.getInstance("AES");// 创建密码器 byte[] byteContent = content.getBytes("utf-8"); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));// 初始化为加密模式的密码器 byte[] result = cipher.doFinal(byteContent);// 加密 return result; } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } return null; } /** * 解密AES加密过的字符串 * * @param content * AES加密过过的内容 * @param key * 秘钥 * @return 明文 */ public static byte[] decrypt(byte[] content, byte[] key) { try { Cipher cipher = Cipher.getInstance("AES");// 创建密码器 cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"));// 初始化为解密模式的密码器 byte[] result = cipher.doFinal(content); return result; // 明文 } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } return null; } /** * 生成一个AES密钥对象 * * @return */ public static SecretKeySpec generateKey() { try { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128, new SecureRandom()); SecretKey secretKey = kgen.generateKey(); byte[] enCodeFormat = secretKey.getEncoded(); SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES"); return key; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } /** * 生成一个AES密钥 * @return */ public static byte[] generateKey2byte() { return generateKey().getEncoded(); } }
RSA工具类:
import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.Cipher; /** * RSA工具类 */ public class RSAUtil { /** * 定义加密方式 */ protected final static String KEY_RSA = "RSA"; /** * 定义签名算法 */ protected final static String KEY_RSA_SIGNATURE = "MD5withRSA"; /** * RSA的私钥 */ protected final static String PRIVATEKEY = "30820276020100300D06092A864886F70D0101010500048202603082025C0201000281810089EBFDC41DE5968A586DD7B91F808E163BCF1A0F427D206A3B80D9D761A09444120229747F59433488CAAA0A99D0F3AF9DE03720251E0BDFF68B28E1C106DD66B7B4C7B7EEE7D2AA2B686695F975621876B33EE4B4641CDDC0B14FBDA96C722D9397D2E8AD74A46AC98B82A8A41F6D9527B3D8DEFB2A60D5A642E4709CFFB2150203010001028181008113A11D27B5B45BA942B37F8761F298104554682F9B96F894D3940C244BFA36727C1F7BEDAB0660661CF562926DA1821BC8B90E966E3642D6238A912CEB55CBE972129393667ED2D97718DBEBA6256394E3700A40202C1568E292E50EB0EAC3E0B838F56AF6F6C118E22EF5B18DB4104A07630CC7F383283B821B0568F82641024100C87B0E203F316D0D73348AA4448F60E87FC9BAEABD23DD33E5E55223706B9267216B5381181A84911FC6EA6A90A6BED10881FE7C8491612B39138FBD33A2B0AD024100B01DDE551696F55AC56F17E4B2E0C64DB6F4B6DD93116AC199959B26999416B553B2212B256846665B7E864310DC70913122A7DAE674C1AD2FD3DEF0FC08EC0902402723F7370E7F5CD62266E0A67F882A9859D28DBEA49CAAE425FF26912AB2A5CBA2B7AC7EE8B0CCAEF4B04635F5F5C80D5186E7A371D25C512EFC85B49FAF24A5024035F8B14DFA2241069442BB5BC6C5C37FC575B124AE11445A182B14E4FB63BAA1CF0863C9C928EF8A26B7DB856A01642DDA94F843C92436C65045E9A8885463A10240762C26ED98A3B0F07A6E5E38E3C23A59C6BD1F3CFDF4DD4545CDF5FE5191DD90CAAD8922447E6F65CE33E2040C9A2638EC2C54B9D6DBBC16974653E89BC520C8"; /** * RSA的公钥 */ public final static String PUBLICKEY = "30819F300D06092A864886F70D010101050003818D003081890281810089EBFDC41DE5968A586DD7B91F808E163BCF1A0F427D206A3B80D9D761A09444120229747F59433488CAAA0A99D0F3AF9DE03720251E0BDFF68B28E1C106DD66B7B4C7B7EEE7D2AA2B686695F975621876B33EE4B4641CDDC0B14FBDA96C722D9397D2E8AD74A46AC98B82A8A41F6D9527B3D8DEFB2A60D5A642E4709CFFB2150203010001"; /** * 用私钥对信息生成数字签名 * * @param data * 加密数据 * @param privateKey * 私钥 * @return */ public static String sign(byte[] data, String privateKey) { String str = ""; try { // 解密16进制的二进制数的私钥 byte[] bytes = EncryptUtil.parseHexStr2Byte(privateKey); // 构造PKCS8EncodedKeySpec对象 PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(bytes); // 指定的加密算法 KeyFactory factory = KeyFactory.getInstance(KEY_RSA); // 取私钥对象 PrivateKey key = factory.generatePrivate(pkcs); // 用私钥对信息生成数字签名 Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE); signature.initSign(key); signature.update(data); str = EncryptUtil.parseByte2HexStr(signature.sign()); } catch (Exception e) { e.printStackTrace(); } return str; } /** * 校验数字签名 * * @param data * 加密数据 * @param publicKey * 公钥 * @param sign * 数字签名 * @return 校验成功返回true,失败返回false */ public static boolean verify(byte[] data, String publicKey, String sign) { boolean flag = false; try { // 解密16进制的二进制数的私钥 byte[] bytes = EncryptUtil.parseHexStr2Byte(publicKey); // 构造X509EncodedKeySpec对象 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes); // 指定的加密算法 KeyFactory factory = KeyFactory.getInstance(KEY_RSA); // 取公钥对象 PublicKey key = factory.generatePublic(keySpec); // 用公钥验证数字签名 Signature signature = Signature.getInstance(KEY_RSA_SIGNATURE); signature.initVerify(key); signature.update(data); flag = signature.verify(EncryptUtil.parseHexStr2Byte(sign)); } catch (Exception e) { e.printStackTrace(); } return flag; } /** * 私钥解密 * * @param data * 加密数据 * @param key * 私钥 * @return */ public static byte[] decryptByPrivateKey(byte[] data, String key) { byte[] result = null; try { // 对私钥解密 byte[] bytes = EncryptUtil.parseHexStr2Byte(key); // 取得私钥 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes); KeyFactory factory = KeyFactory.getInstance(KEY_RSA); PrivateKey privateKey = factory.generatePrivate(keySpec); // 对数据解密 Cipher cipher = Cipher.getInstance(factory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateKey); result = cipher.doFinal(data); } catch (Exception e) { e.printStackTrace(); } return result; } /** * 私钥加密 * * @param data * 待加密数据 * @param key * 私钥 * @return */ public static byte[] encryptByPrivateKey(byte[] data, String key) { byte[] result = null; try { byte[] bytes = EncryptUtil.parseHexStr2Byte(key); // 取得私钥 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes); KeyFactory factory = KeyFactory.getInstance(KEY_RSA); PrivateKey privateKey = factory.generatePrivate(keySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(factory.getAlgorithm());//注意客户端(Linux)与服务端(Wendows)的区别 cipher.init(Cipher.ENCRYPT_MODE, privateKey); result = cipher.doFinal(data); } catch (Exception e) { e.printStackTrace(); } return result; } /** * 公钥解密 * * @param data * 加密数据 * @param key * 公钥 * @return */ public static byte[] decryptByPublicKey(byte[] data, String key) { byte[] result = null; try { // 对公钥解密 byte[] bytes = EncryptUtil.parseHexStr2Byte(key); // 取得公钥 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes); KeyFactory factory = KeyFactory.getInstance(KEY_RSA); PublicKey publicKey = factory.generatePublic(keySpec); // 对数据解密 由于服务器与安卓底层不同 使用factory.getAlgorithm()解密失败 Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, publicKey); result = cipher.doFinal(data); } catch (Exception e) { e.printStackTrace(); } return result; } /** * 公钥加密 * * @param data * 待加密数据 * @param key * 公钥 * @return */ public static byte[] encryptByPublicKey(byte[] data, String key) { byte[] result = null; try { byte[] bytes = EncryptUtil.parseHexStr2Byte(key); // 取得公钥 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes); KeyFactory factory = KeyFactory.getInstance(KEY_RSA); PublicKey publicKey = factory.generatePublic(keySpec); // 对数据加密 注意点: Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); result = cipher.doFinal(data); } catch (Exception e) { e.printStackTrace(); } return result; } }
解密工具类:
/** * 解密工具类 */ public class EncryptUtil { /** * 解密 对二进制的解密 * @param aeskey * AES通过RSA加密后的秘钥 * @param content * AES加密的密文 */ public static byte[] aesAndRsaDecrypt(byte[] aeskey, byte[] content) { // 1.使用RSA私钥解密接收到的AES秘钥密文 byte[] aeskey1 = RSAUtil.decryptByPrivateKey(aeskey, RSAUtil.PUBLICKEY); // 2.再使用解密到的AES秘钥对接收到的数据进行解密 return AESUtil.decrypt(content, aeskey1); } /** * 解密 对字符串类型的 * @param aeskey * AES通过RSA加密后的秘钥 * @param content * AES加密的密文 * @throws Exception */ public static byte[] aesAndRsaDecrypt(String aeskey, String content){ return aesAndRsaDecrypt(EncryptUtil.parseHexStr2Byte(aeskey), EncryptUtil.parseHexStr2Byte(content)); } /** * 获取使用AES加密后的内容 * @param content * @return */ public static String getEncryptContext(byte[] content,byte[] aes_key){ // 1.AES秘钥加密需要传输的数据 byte[] byte_context = AESUtil.decrypt(content, aes_key); return EncryptUtil.parseByte2HexStr(byte_context); } /** * 将二进制转换成16进制 * * @param buf * @return */ public static String parseByte2HexStr(byte buf[]) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < buf.length; i++) { String hex = Integer.toHexString(buf[i] & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } sb.append(hex.toUpperCase()); } return sb.toString(); } /** * 将16进制转换为二进制 * * @param hexStr * @return */ public static byte[] parseHexStr2Byte(String hexStr) { if (hexStr.length() < 1) return null; byte[] result = new byte[hexStr.length() / 2]; for (int i = 0; i < hexStr.length() / 2; i++) { int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); result[i] = (byte) (high * 16 + low); } return result; } }
使用RSA在自己本地能解密与加密,自己加密后到服务器解密失败的原因 可参考:http://blog.csdn.net/libraryhu/article/details/50821791
使用如下:
//加密的处理,RSA加密AES钥匙,再用AES加密内容 //生成AES秘钥 byte[] aeskey = AESUtil.generateKey2byte(); //RSA加密AES的秘钥 byte[] aeskeyToRsa = RSAUtil.encryptByPublicKey(aeskey, RSAUtil.PUBLICKEY); OkHttpUtils .get() .url(login) .addParams("key", EncryptUtil.parseByte2HexStr(aeskeyToRsa))//将加了密的AES秘钥给服务器 //用户名与密码的加密 .addParams("username", AESUtil.encrypt2String(username, aeskey))//再用AES加密内容 .addParams("password", AESUtil.encrypt2String(password, aeskey)) .addParams("loginType", "E") .build()
android RSA和Java RSA加密不一致的坑
byte[]转String 与 String转byte[], 避免数据丢失的正确转换方式:
private final static byte[] aesKey = Base64.decode("SWp6DMurpjXYlR5oJf1F4q89OzHmE3Xo/iMqUfFY1H0=",Base64.DEFAULT); new String(aesKey,"ISO-8859-1") new String(aesKey,"ISO-8859-1").getBytes("ISO-8859-1") Base64.encodeToString(new String(aesKey,"ISO-8859-1").getBytes("ISO-8859-1"),Base64.DEFAULT)
也就是需要通过ISO-8859-1 来转换