# [转载] 对称加密与非对称加密

## 背景

http://www.cnblogs.com/jfzhu/p/4020928.html

## 原文

### （一）对称加密（Symmetric Cryptography）

2000年10月2日，美国国家标准与技术研究所（NIST–American National Institute of Standards and Technology）选择了Rijndael算法作为新的高级加密标准（AES–Advanced Encryption Standard）。.NET中包含了Rijndael算法，类名叫RijndaelManaged，下面举个例子。

``````private string myData = "hello";
private byte[] cipherText;
private byte[] salt = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0 };

private void mnuSymmetricEncryption_Click(object sender, RoutedEventArgs e)
{
var key = new Rfc2898DeriveBytes(myPassword, salt);
// Encrypt the data.
var algorithm = new RijndaelManaged();
algorithm.Key = key.GetBytes(16);
algorithm.IV = key.GetBytes(16);
var sourceBytes = new System.Text.UnicodeEncoding().GetBytes(myData);
using (var sourceStream = new MemoryStream(sourceBytes))
using (var destinationStream = new MemoryStream())
using (var crypto = new CryptoStream(sourceStream, algorithm.CreateEncryptor(), CryptoStreamMode.Read))
{
moveBytes(crypto, destinationStream);
cipherText = destinationStream.ToArray();
}
MessageBox.Show(String.Format("Data:{0}{1}Encrypted and Encoded:{2}", myData, Environment.NewLine, Convert.ToBase64String(cipherText)));
}
private void moveBytes(Stream source, Stream dest)
{
byte[] bytes = new byte[2048];
var count = source.Read(bytes, 0, bytes.Length);
while (0 != count)
{
dest.Write(bytes, 0, count);
}
}
``````

``````private void mnuSymmetricDecryption_Click(object sender, RoutedEventArgs e)
{
if (cipherText == null)
{
MessageBox.Show("Encrypt Data First!");
return;
}
var key = new Rfc2898DeriveBytes(myPassword, salt);
// Try to decrypt, thus showing it can be round-tripped.
var algorithm = new RijndaelManaged();
algorithm.Key = key.GetBytes(16);
algorithm.IV = key.GetBytes(16);
using (var sourceStream = new MemoryStream(cipherText))
using (var destinationStream = new MemoryStream())
using (var crypto = new CryptoStream(sourceStream, algorithm.CreateDecryptor(), CryptoStreamMode.Read))
{
moveBytes(crypto, destinationStream);
var decryptedBytes = destinationStream.ToArray();
var decryptedMessage = new UnicodeEncoding().GetString(
decryptedBytes);
MessageBox.Show(decryptedMessage);
}
}
``````

### （二）非对称加密（Asymmetric Cryptography）

``````private byte[] rsaCipherText;
private void mnuAsymmetricEncryption_Click(object sender, RoutedEventArgs e)
{
var rsa = 1;
// Encrypt the data.
var cspParms = new CspParameters(rsa);
cspParms.Flags = CspProviderFlags.UseMachineKeyStore;
cspParms.KeyContainerName = "My Keys";
var algorithm = new RSACryptoServiceProvider(cspParms);
var sourceBytes = new UnicodeEncoding().GetBytes(myData);
rsaCipherText = algorithm.Encrypt(sourceBytes, true);
MessageBox.Show(String.Format("Data: {0}{1}Encrypted and Encoded: {2}",
myData, Environment.NewLine,
Convert.ToBase64String(rsaCipherText)));
}
``````

``````private void mnuAsymmetricDecryption_Click(object sender, RoutedEventArgs e)
{
if(rsaCipherText==null)
{
MessageBox.Show("Encrypt First!");
return;
}
var rsa = 1;
// decrypt the data.
var cspParms = new CspParameters(rsa);
cspParms.Flags = CspProviderFlags.UseMachineKeyStore;
cspParms.KeyContainerName = "My Keys";
var algorithm = new RSACryptoServiceProvider(cspParms);
var unencrypted = algorithm.Decrypt(rsaCipherText, true);
MessageBox.Show(new UnicodeEncoding().GetString(unencrypted));
}
``````

（1） Alice需要在银行的网站做一笔交易，她的浏览器首先生成了一个随机数作为对称密钥。

（2） Alice的浏览器向银行的网站请求公钥。

（3） 银行将公钥发送给Alice。

（4） Alice的浏览器使用银行的公钥将自己的对称密钥加密。

（5） Alice的浏览器将加密后的对称密钥发送给银行。

（6） 银行使用私钥解密得到Alice浏览器的对称密钥。

（7） Alice与银行可以使用对称密钥来对沟通的内容进行加密与解密了。

### （三）总结

（1） 对称加密加密与解密使用的是同样的密钥，所以速度快，但由于需要将密钥在网络传输，所以安全性不高。

（2） 非对称加密使用了一对密钥，公钥与私钥，所以安全性高，但加密与解密速度慢。

（3） 解决的办法是将对称加密的密钥使用非对称加密的公钥进行加密，然后发送出去，接收方使用私钥进行解密得到对称加密的密钥，然后双方可以使用对称加密来进行沟通。

（4） PostgreSQL pgcrypto插件支持了对称和非对称加密。

https://www.postgresql.org/docs/devel/static/pgcrypto.html

pgcrypto的加解密过程参考:

The functions here implement the encryption part of the OpenPGP (RFC 4880) standard. Supported are both symmetric-key and public-key encryption.

An encrypted PGP message consists of 2 parts, or packets:

• Packet containing a session key - either symmetric-key or public-key encrypted.

• Packet containing data encrypted with the session key.

When encrypting with a symmetric key (i.e., a password):

1. The given password is hashed using a String2Key (S2K) algorithm. This is rather similar to crypt() algorithms - purposefully slow and with random salt - but it produces a full-length binary key.

2. If a separate session key is requested, a new random key will be generated. Otherwise the S2K key will be used directly as the session key.

3. If the S2K key is to be used directly, then only S2K settings will be put into the session key packet. Otherwise the session key will be encrypted with the S2K key and put into the session key packet.

When encrypting with a public key:

1. A new random session key is generated.

2. It is encrypted using the public key and put into the session key packet.

In either case the data to be encrypted is processed as follows:

1. Optional data-manipulation: compression, conversion to UTF-8, and/or conversion of line-endings.

2. The data is prefixed with a block of random bytes. This is equivalent to using a random IV.

3. An SHA1 hash of the random prefix and data is appended.

4. All this is encrypted with the session key and placed in the data packet.

### 定义

1976年，美国学者Dime和Henman为解决信息公开传送和密钥管理问题，提出一种新的密钥交换协议，允许在不安全的媒体上的通讯双方交换信息，安全地达成一致的密钥，这就是“公开密钥系统”。

### 工作过程

1、乙方生成一对密钥（公钥和私钥）并将公钥向其它方公开。

2、得到该公钥的甲方使用该密钥对机密信息进行加密后再发送给乙方。

3、乙方再用自己保存的另一把专用密钥（私钥）对加密后的信息进行解密。乙方只能用其专用密钥（私钥）解密由对应的公钥加密后的信息。

## 参考

http://www.cnblogs.com/jfzhu/p/4020928.html

https://www.postgresql.org/docs/devel/static/pgcrypto.html

https://baike.baidu.com/item/%E9%9D%9E%E5%AF%B9%E7%A7%B0%E5%8A%A0%E5%AF%86

Tags:

Updated: