作为程序员一定要保持良好的睡眠,才能好编程

利用openssl 进行Base64 对AES/DES/3DES/RSA 加解密 使用小结

发布时间:2019-03-22

互联网中,数据交互 数据安全是非常重要的,为了数据的安全,存储在cookie及redis、session中的值是什么样的?

正常情况下,就是数据本身,没有经过加密的,


但是根据项目的安全,数据的安全日益重要起来。


这就需要对数据进行加解密处理了,


部分说明:


RSA公钥与钥匙生成方式


生成的每一行代码都是64位长度的字符串



openssl函数使用方法


openssl.png


先了解下 加密、解密常用的方式有哪几种:


加密基础

学习如何使用加密之前,我们需要了解一些加密相关的基础知识。

加密算法一般分为两种:对称加密算法和非对称加密算法。

对称加密

对称加密算法是消息发送者和接收者使用同一个密匙,发送者使用密匙加密了文件,接收者使用同样的密匙解密,获取信息。常见的对称加密算法有:des/aes/3des.

对称加密算法的特点有:速度快,加密前后文件大小变化不大,但是密匙的保管是个大问题,因为消息发送方和接收方任意一方的密匙丢失,都会导致信息传输变得不安全。

非对称加密

与对称加密相对的是非对称加密,非对称加密的核心思想是使用一对相对的密匙,分为公匙和私匙,私匙自己安全保存,而将公匙公开。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密;如果用私钥对数据进行加密,那么只有用对应的公钥才能解密。发送数据前只需要使用接收方的公匙加密就行了。常见的非对称加密算法有RSA/DSA:

非对称加密虽然没有密匙保存问题,但其计算量大,加密速度很慢,有时候我们还需要对大块数据进行分块加密。

数字签名

为了保证数据的完整性,还需要通过散列函数计算得到一个散列值,这个散列值被称为数字签名。其特点有:

无论原始数据是多大,结果的长度相同的;
输入一样,输出也相同;
对输入的微小改变,会使结果产生很大的变化;
加密过程不可逆,无法通过散列值得到原来的数据;

常见的数字签名算法有md5,hash1等算法。

PHP的openssl扩展

openssl扩展使用openssl加密扩展包,封装了多个用于加密解密相关的PHP函数,极大地方便了对数据的加密解密。 常用的函数有:

对称加密相关:

string openssl_encrypt ( string $data , string $method , string $password)

其中$data为其要加密的数据,$method是加密要使用的方法,$password是要使用的密匙,函数返回加密后的数据;

其中$method列表可以使用openssl_get_cipher_methods()来获取,我们选取其中一个使用,$method列表形如:

Array(
  0 => aes-128-cbc,  // aes加密
  1 => des-ecb,    // des加密
  2 => des-ede3,   // 3des加密
  )
其解密函数为 string openssl_encrypt ( string $data , string $method , string $password)

非对称加密相关:

RSA加减密

 
openssl_public_encrypt(string $data , string &$crypted , mixed $key [, int $padding = OPENSSL\_PKCS1\_PADDING ] )
使用公匙加密数据,其中$data是要加密的数据;$crypted是一个引用变量,加密后的数据会被放入这个变量中;$key是要传入的公匙数据;由于被加密数据分组时,有可能不会正好为加密位数bit的整数倍,所以需要$padding(填充补齐),$padding的可选项有 OPENSSL_PKCS1_PADDING, OPENSSL_NO_PADDING,分别为PKCS1填充,或不使用填充;

 
加密实例

以下是一个加减密使用的小例子:

//var_dump(openssl_get_cipher_methods());

var_dump(openssl_cipher_iv_length('des-ede3')); //得到这个加密方法需要的 位数

$iv = openssl_random_pseudo_bytes(16); //需要知道加密iv 的向量的位数

$des3 = base64_encode(openssl_encrypt('songyongzhan', 'des-ede3', 'abcd444444444444', OPENSSL_RAW_DATA));
//$des3_cbc = base64_encode(openssl_encrypt('songyongzhan', 'des-ede3-cbc', 'abcd444444444444', 0, $iv));

var_dump($des3);
//var_dump($des3_cbc);
//
//

echo sprintf("DES-CBC length:%s\n", openssl_cipher_iv_length('DES-CBC'));
echo sprintf("des-ecb length:%s\n", openssl_cipher_iv_length('des-ecb'));
$desecb = base64_encode(openssl_encrypt('songyongzhan', 'des-ecb', 'abcd444444444444', OPENSSL_RAW_DATA));
$desecb2 = base64_encode(openssl_encrypt('songyongzhan', 'des-ecb', 'abcd444444444444'));

echo sprintf("desecb:%s  ---length: %d ^^^^ desecb2:%s  ---length: %d \n", $desecb, strlen($desecb), $desecb2, strlen($desecb2));
echo sprintf("desecb:%s ^^^^ desecb2解密:%s \n", openssl_decrypt(base64_decode($desecb), 'des-ecb', 'abcd444444444444', OPENSSL_RAW_DATA), openssl_decrypt(base64_decode($desecb2), 'des-ecb', 'abcd444444444444'));

/**
 * openssl_encrypt 加密出来字符串随 要加密的数据长度 而变化, 加密数据越大 生成的加密字符串越长。
 *
 * 第四个参数 options  如果不 为0   一般情况下 传OPENSSL_RAW_DATA
 *
 * $iv 向量  长度根据   openssl_cipher_iv_length('des-ecb');  根据这这个方法返回的长度 使用 openssl_random_pseudo_bytes($length);
 * 去自动生成$iv。 如果长度为 0 则不需要传递。
 * $fun='des-ecb';
 *
 * if($num=openssl_cipher_iv_length($fun))
 *  $iv=openssl_random_pseudo_bytes($num);
 * else
 *  $iv='';
 *
 * 这样就会拿到一个最合适的iv
 *
 *
 *
 */

//var_dump($v);
$data = openssl_encrypt('b', 'aes-128-cbc', 'abcd', 0, $iv);
//$data = openssl_encrypt('songyongzhan', 'aes-128-cbc', 'abcd', OPENSSL_RAW_DATA);
$data = base64_encode($data);
var_dump($data);

$re = openssl_decrypt(base64_decode($data), 'aes-128-cbc', 'abcd', 0, $iv);
//$re = openssl_decrypt(base64_decode($data), 'aes-128-cbc', 'abcd', OPENSSL_RAW_DATA);

var_dump($re);

var_dump(openssl_get_publickey());
/**
 * array(182) {
[0]=>
string(11) "AES-128-CBC"
[1]=>
string(11) "AES-128-CFB"
[2]=>
string(12) "AES-128-CFB1"
[3]=>
string(12) "AES-128-CFB8"
[4]=>
string(11) "AES-128-CTR"
[5]=>
string(11) "AES-128-ECB"
[6]=>
string(11) "AES-128-OFB"
[7]=>
string(11) "AES-128-XTS"
[8]=>
string(11) "AES-192-CBC"
[9]=>
string(11) "AES-192-CFB"
[10]=>
string(12) "AES-192-CFB1"
[11]=>
string(12) "AES-192-CFB8"
[12]=>
string(11) "AES-192-CTR"
[13]=>
string(11) "AES-192-ECB"
[14]=>
string(11) "AES-192-OFB"
[15]=>
string(11) "AES-256-CBC"
[16]=>
string(11) "AES-256-CFB"
[17]=>
string(12) "AES-256-CFB1"
[18]=>
string(12) "AES-256-CFB8"
[19]=>
string(11) "AES-256-CTR"
[20]=>
string(11) "AES-256-ECB"
[21]=>
string(11) "AES-256-OFB"
[22]=>
string(11) "AES-256-XTS"
[23]=>
string(6) "BF-CBC"
[24]=>
string(6) "BF-CFB"
[25]=>
string(6) "BF-ECB"
[26]=>
string(6) "BF-OFB"
[27]=>
string(16) "CAMELLIA-128-CBC"
[28]=>
string(16) "CAMELLIA-128-CFB"
[29]=>
string(17) "CAMELLIA-128-CFB1"
[30]=>
string(17) "CAMELLIA-128-CFB8"
[31]=>
string(16) "CAMELLIA-128-ECB"
[32]=>
string(16) "CAMELLIA-128-OFB"
[33]=>
string(16) "CAMELLIA-192-CBC"
[34]=>
string(16) "CAMELLIA-192-CFB"
[35]=>
string(17) "CAMELLIA-192-CFB1"
[36]=>
string(17) "CAMELLIA-192-CFB8"
[37]=>
string(16) "CAMELLIA-192-ECB"
[38]=>
string(16) "CAMELLIA-192-OFB"
[39]=>
string(16) "CAMELLIA-256-CBC"
[40]=>
string(16) "CAMELLIA-256-CFB"
[41]=>
string(17) "CAMELLIA-256-CFB1"
[42]=>
string(17) "CAMELLIA-256-CFB8"
[43]=>
string(16) "CAMELLIA-256-ECB"
[44]=>
string(16) "CAMELLIA-256-OFB"
[45]=>
string(9) "CAST5-CBC"
[46]=>
string(9) "CAST5-CFB"
[47]=>
string(9) "CAST5-ECB"
[48]=>
string(9) "CAST5-OFB"
[49]=>
string(7) "DES-CBC"
[50]=>
string(7) "DES-CFB"
[51]=>
string(8) "DES-CFB1"
[52]=>
string(8) "DES-CFB8"
[53]=>
string(7) "DES-ECB"
[54]=>
string(7) "DES-EDE"
[55]=>
string(11) "DES-EDE-CBC"
[56]=>
string(11) "DES-EDE-CFB"
[57]=>
string(11) "DES-EDE-OFB"
[58]=>
string(8) "DES-EDE3"
[59]=>
string(12) "DES-EDE3-CBC"
[60]=>
string(12) "DES-EDE3-CFB"
[61]=>
string(13) "DES-EDE3-CFB1"
[62]=>
string(13) "DES-EDE3-CFB8"
[63]=>
string(12) "DES-EDE3-OFB"
[64]=>
string(7) "DES-OFB"
[65]=>
string(8) "DESX-CBC"
[66]=>
string(8) "IDEA-CBC"
[67]=>
string(8) "IDEA-CFB"
[68]=>
string(8) "IDEA-ECB"
[69]=>
string(8) "IDEA-OFB"
[70]=>
string(10) "RC2-40-CBC"
[71]=>
string(10) "RC2-64-CBC"
[72]=>
string(7) "RC2-CBC"
[73]=>
string(7) "RC2-CFB"
[74]=>
string(7) "RC2-ECB"
[75]=>
string(7) "RC2-OFB"
[76]=>
string(3) "RC4"
[77]=>
string(6) "RC4-40"
[78]=>
string(12) "RC4-HMAC-MD5"
[79]=>
string(8) "SEED-CBC"
[80]=>
string(8) "SEED-CFB"
[81]=>
string(8) "SEED-ECB"
[82]=>
string(8) "SEED-OFB"
[83]=>
string(11) "aes-128-cbc"
[84]=>
string(11) "aes-128-ccm"
[85]=>
string(11) "aes-128-cfb"
[86]=>
string(12) "aes-128-cfb1"
[87]=>
string(12) "aes-128-cfb8"
[88]=>
string(11) "aes-128-ctr"
[89]=>
string(11) "aes-128-ecb"
[90]=>
string(11) "aes-128-gcm"
[91]=>
string(11) "aes-128-ofb"
[92]=>
string(11) "aes-128-xts"
[93]=>
string(11) "aes-192-cbc"
[94]=>
string(11) "aes-192-ccm"
[95]=>
string(11) "aes-192-cfb"
[96]=>
string(12) "aes-192-cfb1"
[97]=>
string(12) "aes-192-cfb8"
[98]=>
string(11) "aes-192-ctr"
[99]=>
string(11) "aes-192-ecb"
[100]=>
string(11) "aes-192-gcm"
[101]=>
string(11) "aes-192-ofb"
[102]=>
string(11) "aes-256-cbc"
[103]=>
string(11) "aes-256-ccm"
[104]=>
string(11) "aes-256-cfb"
[105]=>
string(12) "aes-256-cfb1"
[106]=>
string(12) "aes-256-cfb8"
[107]=>
string(11) "aes-256-ctr"
[108]=>
string(11) "aes-256-ecb"
[109]=>
string(11) "aes-256-gcm"
[110]=>
string(11) "aes-256-ofb"
[111]=>
string(11) "aes-256-xts"
[112]=>
string(6) "bf-cbc"
[113]=>
string(6) "bf-cfb"
[114]=>
string(6) "bf-ecb"
[115]=>
string(6) "bf-ofb"
[116]=>
string(16) "camellia-128-cbc"
[117]=>
string(16) "camellia-128-cfb"
[118]=>
string(17) "camellia-128-cfb1"
[119]=>
string(17) "camellia-128-cfb8"
[120]=>
string(16) "camellia-128-ecb"
[121]=>
string(16) "camellia-128-ofb"
[122]=>
string(16) "camellia-192-cbc"
[123]=>
string(16) "camellia-192-cfb"
[124]=>
string(17) "camellia-192-cfb1"
[125]=>
string(17) "camellia-192-cfb8"
[126]=>
string(16) "camellia-192-ecb"
[127]=>
string(16) "camellia-192-ofb"
[128]=>
string(16) "camellia-256-cbc"
[129]=>
string(16) "camellia-256-cfb"
[130]=>
string(17) "camellia-256-cfb1"
[131]=>
string(17) "camellia-256-cfb8"
[132]=>
string(16) "camellia-256-ecb"
[133]=>
string(16) "camellia-256-ofb"
[134]=>
string(9) "cast5-cbc"
[135]=>
string(9) "cast5-cfb"
[136]=>
string(9) "cast5-ecb"
[137]=>
string(9) "cast5-ofb"
[138]=>
string(7) "des-cbc"
[139]=>
string(7) "des-cfb"
[140]=>
string(8) "des-cfb1"
[141]=>
string(8) "des-cfb8"
[142]=>
string(7) "des-ecb"
[143]=>
string(7) "des-ede"
[144]=>
string(11) "des-ede-cbc"
[145]=>
string(11) "des-ede-cfb"
[146]=>
string(11) "des-ede-ofb"
[147]=>
string(8) "des-ede3"
[148]=>
string(12) "des-ede3-cbc"
[149]=>
string(12) "des-ede3-cfb"
[150]=>
string(13) "des-ede3-cfb1"
[151]=>
string(13) "des-ede3-cfb8"
[152]=>
string(12) "des-ede3-ofb"
[153]=>
string(7) "des-ofb"
[154]=>
string(8) "desx-cbc"
[155]=>
string(13) "id-aes128-CCM"
[156]=>
string(13) "id-aes128-GCM"
[157]=>
string(14) "id-aes128-wrap"
[158]=>
string(13) "id-aes192-CCM"
[159]=>
string(13) "id-aes192-GCM"
[160]=>
string(14) "id-aes192-wrap"
[161]=>
string(13) "id-aes256-CCM"
[162]=>
string(13) "id-aes256-GCM"
[163]=>
string(14) "id-aes256-wrap"
[164]=>
string(24) "id-smime-alg-CMS3DESwrap"
[165]=>
string(8) "idea-cbc"
[166]=>
string(8) "idea-cfb"
[167]=>
string(8) "idea-ecb"
[168]=>
string(8) "idea-ofb"
[169]=>
string(10) "rc2-40-cbc"
[170]=>
string(10) "rc2-64-cbc"
[171]=>
string(7) "rc2-cbc"
[172]=>
string(7) "rc2-cfb"
[173]=>
string(7) "rc2-ecb"
[174]=>
string(7) "rc2-ofb"
[175]=>
string(3) "rc4"
[176]=>
string(6) "rc4-40"
[177]=>
string(12) "rc4-hmac-md5"
[178]=>
string(8) "seed-cbc"
[179]=>
string(8) "seed-cfb"
[180]=>
string(8) "seed-ecb"
[181]=>
string(8) "seed-ofb"
}
string(24) "82XWmUHbd/yF9psJhlHPJg=="
string(12) "songyongzhan"
[Finished in 0.2s]
 */



// 获取公匙

$pub_key = openssl_get_publickey('test.pem');
 
$encrypted = '';
// 对数据分块加密
for ($offset = 0, $length = strlen($raw_msg); $offset < $length; $offset += $key_size){  
  $encryptedBlock = '';
  $data = substr($raw_msg, $offset, $key_size)
  if (!openssl_public_encrypt($data, $encryptedBlock, $pub_key, OPENSSL_PKCS1_PADDING)){
    return '';
  } else {
    $encrypted .= $encryptedBlock;
 }
 return $encrypted;


而对称加密就非常简单了,直接使用ssl_encrypt()函数即可;

当然一些接口可能会对加密方法进行不同的要求,如不同的padding,加密块大小等等,这些就需要使用者自己调整了。

 





如果系统是长连接,会话可以通过php直接存入到cookie  

如果单单是接口,那么需要客户端自己存入cookie


简单说明:cookie中的值必须是经过加密处理的。


AES加密 


DES加密



RSA加密


经过AES中的base64_encode加密后,在传输的过程中,

+ 会变成 空格

因此需要对其进行安全转换:

function base64encode($data, $urlsafe = FALSE) {
  $data = base64_encode($data);
  return $urlsafe ? strtr($data, '+/', '-_') : $data;
}

function base64decode($data, $urlsafe = FALSE) {
  return base64_decode($urlsafe ? strtr($data, '-_', '+/') : $data);
}


因此对base64_encode 进行了封装处理,其实就是进行吧 字符的替换工作,这样在传输的过程中就不会出现错误了。

解密的时候,重新把替换的字符替换回来,这两个函数就是做两件事情用的。

随机生成了  openssl_random_pseudo_bytes(16);  16个伪字节符,用于加密更安全

通过16个字符
function AESEncrypt($data, $key, $urlsafe = FALSE) { //openssl_get_cipher_methods
  if ($data && $key) {
    $iv = openssl_random_pseudo_bytes(16);  //随机生成一个伪字节  echo random_bytes(5);
    $data = base64encode($iv . openssl_encrypt($data, 'aes-128-cbc', $key, OPENSSL_RAW_DATA, $iv), $urlsafe);
  }
  return $data;
}


function AESDecrypt($data, $key, $urlsafe = FALSE) {
  if (strlen($data) >= 16 + 16 && $key) {
    $data = base64decode($data, $urlsafe);
    $data = openssl_decrypt(substr($data, 16), 'aes-128-cbc', $key, OPENSSL_RAW_DATA, substr($data, 0, 16));
  }
  return $data;
}


$key="456";

$pass= AESEncrypt('song',$key);

echo $pass;
echo "<br>";

$src=AESDecrypt($pass,$key);

echo $src;

openssl_encrypt()


openssl_decrypt()






--------------------------
DES 加密 

DES3 加密  

以下这两种加密方式,其实也是openssl 加密中的,只不过是 加密的方法不一样, 不要以为是其他的加密方式。


 $data = openssl_encrypt($data, 'des-ecb', $key);
 
 $data = openssl_decrypt($data, 'des-ecb', $key);

就是第二个参数传递不一样。

function DESEncrypt($data, $key, $urlsafe = FALSE) {
  if ($data && $key) {
    $data = openssl_encrypt($data, 'des-ecb', $key);
    $urlsafe && $data = strtr($data, '+/', '-_');
  }
  return $data;
}

function DESDecrypt($data, $key, $urlsafe = FALSE) {
  if ($data && $key) {
    $urlsafe && $data = strtr($data, '-_', '+/');
    $data = openssl_decrypt($data, 'des-ecb', $key);
  }
  return $data;
}


DES3也是一样的方式:

function DES3Encrypt($data, $key, $urlsafe = FALSE) {
  if ($data && $key) {
    $data = openssl_encrypt($data, 'des-ede3', $key);

    $urlsafe && $data = strtr($data, '+/', '-_');
  }

  return $data;
}

function DES3Decrypt($data, $key, $urlsafe = FALSE) {
  if ($data && $key) {
    $urlsafe && $data = strtr($data, '-_', '+/');

    if ($result = openssl_decrypt($data, 'des-ede3', $key, OPENSSL_ZERO_PADDING)) {
      $padding = ord(substr($result, -1)); //DESede/ECB/ISO10126Padding
      $padding <= 8 && $result = substr($result, 0, -$padding);
    }

    return $result;
  }
  else return $data;
}




/**

此方法用于生成 唯一用于id的的,

适用于大并发情况下,生成唯一id

*/


function getGUID() { //32
  if (function_exists('com_create_guid')) return trim(com_create_guid(), '{}');
  else {
    //mt_srand((double) microtime() * 10000);
    $charid = strtoupper(md5(uniqid(rand(), TRUE)));
    $result = substr($charid, 0, 8) . '-' . substr($charid, 8, 4) . '-' . substr($charid, 12, 4)
      . '-' . substr($charid, 16, 4) . '-' . substr($charid, 20, 12);

    return $result;
  }
}