笔记(二十一)——Http、Https、数据加解密

一、Http请求(转载部分HTTP请求报文(请求行、请求头、请求体))
特点:

(1)HTTP是无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

(2)HTTP是媒体独立的:只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送。客户端以及服务器指定使用适合的MIME-type内容类型。

(3)HTTP是无状态:无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

HTTP请求报文

HTTP请求报文由4部分组成(请求行+请求头+请求体+空行):


笔记(二十一)——Http、Https、数据加解密_第1张图片
image

请求行:

①是请求方法,GET和POST是最常见的HTTP方法,除此以外还包括DELETE、HEAD、OPTIONS、PUT、TRACE。

②为请求对应的URL地址,它和报文头的Host属性组成完整的请求URL。

③是协议名称及版本号。

请求头:

④是HTTP的报文头,报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息。

与缓存相关的规则信息,均包含在header中

请求体:

⑤是报文体即请求体,它将一个页面表单中的组件值通过param1=value1¶m2=value2的键值对形式编码成一个格式化串,它承载多个请求参数的数据。不但报文体可以传递请求参数,请求URL也可以通过类似于“/chapter15/user.html? param1=value1¶m2=value2”的方式传递请求参数。

⑥还有一个是跟在请求体后面的空行,其没有实际意义,主要是用来发送回车符和换行符,通知服务器以下不再有请求头。

服务端响应客户端:


笔记(二十一)——Http、Https、数据加解密_第2张图片
image

响应行:

①报文协议及版本;
②状态码及状态描述;

响应头:

③响应报文头,也是由多个属性组成;

响应体:

④响应报文体,即我们真正要的信息数据

二、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
数据加密方式:

  • 对称加密采用对称密码编码技术,也就是编码和解码采用相同描述字符,即加密和解密使用相同的密钥,实现这种加密技术的算法称对称加密算法。对称加密就是将信息和私钥通过某种算法混合在一起。对称加密使用简单,密钥较短,加密和解密过程较快,耗时短,常见的对称加密算法有DES,3DES,lDEA,AES,RC4等。

  • 非对称加密与对称加密不同,其加密算法需要两个密钥:公开密钥(publickey)和私有密钥(private),两者是一对的。如果用公钥加密,只能用私钥才能解密。非对称加密保密性好,但加密和解密花费的时间较长,不适合对大文件加密而只适合对少量的数据加密。常见的非对称加密算法有RSA,ECC,DSA(数字签名)等。

  • Hash算法是一种单向算法,通过Hash算法可以对目标数据生成一段特定长度、唯一的hash值,但是不能通过这个hash值重新计算出原始的数据,因此也称之为摘要算法,经常被用在不需要数据还原的密码加密以及数据完整性校验上,常用的算法有MD2,MD4,MD5,SHA等。
    参考:
    https是如何工作的?
    Retrofit中如何正确的使用https?——如何校验证书保证安全
    详细解析 HTTP 与 HTTPS 的区别

非对称加密是目前在通信方面最安全的做法,SSL/TLS进行HTTP的加密传输流程:
1.[Client]向服务端初次发起请求
2.[Server]生成一对密钥:公钥和私钥,我们称之为“KeyPub-A”,“KeyPri-A”
3.[Server]服务端将公钥KeyPub-A发送到客户端 。
4.[Client]用服务端的公钥KeyPub-A生成一个之后要用到的对称密钥KeyPub-B。
5.[Client]使用公钥KeyPub-A对KeyPub-B进行加密,KeyPub-B是安全的,因为只有服务端有私钥KeyPri-A。
6.[Client]发送两个信息到服务端,用KeyPub-A加密后的KeyPub-B,用KeyPub-B加密的文本信息。
7.[Server]服务端使用私钥KeyPri-A对加密过的KeyPub-B进行解密,得到真正的KeyPub-B。
8.[Server]使用对称秘钥KeyPub-B解密收到的文本信息得到消息正文。之后双方沟通可以使用对称的公钥进行对称加密,而现在的对称加密便是安全的通信了。
总结:Https传输流程是先进行非对称加密,等服务端和客户端建立SSL连接后再进行负荷较轻的对称加密。

整理了一个SSL工具类,CA证书其实就是一对公钥和私钥:

/**
 * https证书SSL配置
 */
public class MySSLSocketClient {

    /**
     * 忽略https证书验证
     * 

* 使用:okhttpBuilder.sslSocketFactory(MySSLSocketClient.getSSLSocketFactory()) * (这种做法是不安全的,没有了验证容易被网络攻击) * * @return * @throws Exception */ public static SSLSocketFactory getSSLSocketFactory() { try { SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, getTrustManager(), new SecureRandom()); return sslContext.getSocketFactory(); } catch (Exception e) { throw new RuntimeException(e); } } //获取TrustManager private static TrustManager[] getTrustManager() { TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) { //直接空白,不校验 } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) { //直接空白,不校验 } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; } } }; return trustAllCerts; } /** * 获取HostnameVerifier *

* 使用:okhttpBuilder.hostnameVerifier(MySSLSocketClient.getHostnameVerifier())放弃hostname校验,是不安全的 * * @return */ public static HostnameVerifier getHostnameVerifier() { HostnameVerifier hostnameVerifier = new HostnameVerifier() { @Override public boolean verify(String s, SSLSession sslSession) { return true; } }; return hostnameVerifier; } /** * https的证书公匙 */ private static String sslPublicKey = ""; /** * 添加ssl验证 *

安全套接层工厂(验证服务端购买的证书、非安卓系统内置的可信任证书) *

使用购买的证书 *

链接::https://www.jianshu.com/p/7a40e874f6c2?utm_source=oschina-app *

使用:okhttpBuilder.sslSocketFactory(getSSLSocketFactory()) * .hostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); */ public static SSLSocketFactory getDefSSLSocketFactory() { try { //初始化SSLContext SSLContext sslContext = SSLContext.getInstance("TLS"); final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } //验证服务端证书的公钥 @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { if (chain == null) { throw new IllegalArgumentException("checkServerTrusted:x509Certificate array isnull"); } if (!(chain.length > 0)) { throw new IllegalArgumentException("checkServerTrusted: X509Certificate is empty"); } if (!(!TextUtils.isEmpty(authType) && authType.toUpperCase().contains("RSA"))) { throw new CertificateException("checkServerTrusted: AuthType is not RSA"); } // Perform customary SSL/TLS checks try { TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); tmf.init((KeyStore) null); for (TrustManager trustManager : tmf.getTrustManagers()) { ((X509TrustManager) trustManager).checkServerTrusted(chain, authType); } } catch (Exception e) { throw new CertificateException(e); } // Hack ahead: BigInteger and toString(). We know a DER encoded Public Key begins // with 0×30 (ASN.1 SEQUENCE and CONSTRUCTED), so there is no leading 0×00 to drop. RSAPublicKey pubkey = (RSAPublicKey) chain[0].getPublicKey(); //* signum:1表示是正数;radix:16表示字节数组转16进制 String encoded = new BigInteger(1, pubkey.getEncoded()).toString(16); final boolean expected = sslPublicKey.equalsIgnoreCase(encoded); //验证服务端证书的公钥 if (!expected) { throw new CertificateException("checkServerTrusted: got error public key:" + encoded); } } @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[0]; } }}; //将随机数等加密之后传给服务端。 sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); return sslContext.getSocketFactory(); } //省略各种异常处理,请自行添加 catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } return null; } /** * 添加ssl验证 *

安全套接层工厂(信任服务端证书的根证书) *

载入证书 *

链接:https://www.jianshu.com/p/f2097616e65e、 *

https://blog.csdn.net/dd864140130/article/details/52625666 *

使用:okhttpBuilder.socketFactory(getSSLSocketFactory(context, certficates)); * * @param context * @param certificates 放在res/raw目录下的.bks格式证书 * @return */ protected static SSLSocketFactory getSSLSocketFactory(Context context, int[] certificates) { if (context == null) { throw new NullPointerException("context == null"); } //CertificateFactory用来证书生成 CertificateFactory certificateFactory; try { certificateFactory = CertificateFactory.getInstance("X.509"); //Create a KeyStore containing our trusted CAs KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null, null); for (int i = 0; i < certificates.length; i++) { //读取本地证书 InputStream is = context.getResources().openRawResource(certificates[i]); keyStore.setCertificateEntry(String.valueOf(i), certificateFactory.generateCertificate(is)); if (is != null) { is.close(); } } //Create a TrustManager that trusts the CAs in our keyStore TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); //Create an SSLContext that uses our TrustManager SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom()); return sslContext.getSocketFactory(); } catch (Exception e) { } return null; } }

三、3DES加解密

/**
 *
 * 

* Describe:3DES加解密 * *

* eg: String msg = "3DES加密解密案例"; *

* System.out.println("【加密前】:" + msg); *

* //-----加密------ *

* byte[] secretArr = SecretUtils.encryptMode(msg.getBytes()); *

* System.out.println("【加密后】:" + new String(secretArr)); *

* //-----解密------ *

* byte[] myMsgArr = SecretUtils.decryptMode(secretArr); *

* System.out.println("【解密后】:" + new String(myMsgArr)); */ public class SecretUtils { //定义加密算法,有DES、DESede(即3DES)、Blowfish private static final String Algorithm = "DESede"; private static final String PASSWORD_CRYPT_KEY = "V7OIDy10yhwnfLI10yutvtgjUYPewVZQ"; //编码 private static final String CHARSET = "UTF-8"; /** * 加密方法 * * @param src 源数据的字节数组 * @return */ public static byte[] encryptMode(byte[] src) { try { //生成密钥 SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm); //实例化负责加密/解密的Cipher工具类 Cipher c1 = Cipher.getInstance(Algorithm); //初始化为加密模式 c1.init(Cipher.ENCRYPT_MODE, deskey); return c1.doFinal(src); } catch (java.security.NoSuchAlgorithmException e1) { e1.printStackTrace(); } catch (javax.crypto.NoSuchPaddingException e2) { e2.printStackTrace(); } catch (java.lang.Exception e3) { e3.printStackTrace(); } return null; } /** * 解密函数 * * @param src 密文的字节数组 * @return */ public static byte[] decryptMode(byte[] src) { try { SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm); Cipher c1 = Cipher.getInstance(Algorithm); //初始化为解密模式 c1.init(Cipher.DECRYPT_MODE, deskey); return c1.doFinal(src); } catch (java.security.NoSuchAlgorithmException e1) { e1.printStackTrace(); } catch (javax.crypto.NoSuchPaddingException e2) { e2.printStackTrace(); } catch (java.lang.Exception e3) { e3.printStackTrace(); } return null; } /* * 根据字符串生成密钥字节数组 * @param keyStr 密钥字符串 * @return * @throws UnsupportedEncodingException */ public static byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException { //声明一个24位的字节数组,默认里面都是0 byte[] key = new byte[24]; //将字符串转成字节数组 byte[] temp = keyStr.getBytes(CHARSET); /* * 执行数组拷贝 * System.arraycopy(源数组,从源数组哪里开始拷贝,目标数组,拷贝多少位) */ if (key.length > temp.length) { //如果temp不够24位,则拷贝temp数组整个长度的内容到key数组中 System.arraycopy(temp, 0, key, 0, temp.length); } else { //如果temp大于24位,则拷贝temp数组24个长度的内容到key数组中 System.arraycopy(temp, 0, key, 0, key.length); } return key; } }

你可能感兴趣的:(笔记(二十一)——Http、Https、数据加解密)