Brief introduction.NET encryption and decryption realization method sharing

  • 2020-07-21 07:31:46
  • OfStack

.ES1en merges the previously separate API and SDK into one framework, which is of great benefit to program developers. It ADAPTS CryptoAPI to the System.Security.Cryptography namespace of.NET, freeing the password service from the mystique of the SDK platform and turning it into a simple.NET namespace. Since the password service is much easier to implement with the entire framework component being Shared, it is now only necessary to learn the functions of the System.Security.Cryptography namespace and the classes used for a particular solution.
Encryption and decryption algorithms

The ES17en.Security.Cryptography namespace contains classes that implement security schemes, such as encrypting and decrypting data, managing keys, verifying data integrity, and ensuring that the data has not been tampered with, and so on. This article focuses on encryption and decryption.

The encryption and decryption algorithms are divided into symmetric (symmetric) algorithm and asymmetric (asymmetric) algorithm. Symmetric algorithms use the same keys and initialization vectors when encrypting and decrypting data, typically DES, TripleDES, and Rijndael algorithms, which are suitable for situations where there is no need to pass a key and are mainly used for encryption of local documents or data. Asymmetric algorithms have two different keys, the public key, which is passed across the network to encrypt data, and the private key to decrypt data. The asymmetric algorithms mainly include RSA and DSA, which are mainly used for network data encryption.

Encrypt and decrypt local documents

The following example is to encrypt and decrypt local text using the Rijndael symmetric algorithm.

Symmetric algorithms encrypt data as it passes through the system. So you first need to set up a normal stream (for example, I/O streams). The article USES the FileStream class to read text files into byte arrays and also USES this class as an output mechanism.

Next, define the corresponding object variables. We can specify any one of the symmetric encryption algorithm providers when defining object variables for the SymmetricAlgorithm abstract class. The code USES the Rijndael algorithm, but could easily be changed to DES or TripleDES. .ES45en USES a powerful random key to set up an instance of the provider. It is more dangerous to choose your own key. It is a better choice to accept a computer generated key.

In the next step, the algorithm instance provides an object to perform the actual data transfer. Each algorithm has two methods, CreateEncryptor and CreateDecryptor, which return objects that implement the ICryptoTransform interface.

Finally, you now read the source file using BinaryReader's ReadBytes method, which returns an array of 1 bytes. BinaryReader reads the input stream of the source file and calls the ReadBytes method when it is a parameter to the ES56en.Write method. The specified instance of CryptoStream is told that it should operate on the lower laminar flow, which will perform data passing, regardless of whether the purpose of the flow is read or write.

Here is the source snippet for encrypting and decrypting 1 text file:


namespace com.billdawson.crypto
{
class TextFileCrypt
{
public static void Main(string[] args)
{
string file = args[0];
string tempfile = Path.GetTempFileName();
// Opens the specified file 
FileStream fsIn = File.Open(file,FileMode.Open,
FileAccess.Read);
FileStream fsOut = File.Open(tempfile, FileMode.Open,
FileAccess.Write);
// Define symmetric algorithm object instances and interfaces 
SymmetricAlgorithm symm = new RijndaelManaged();
ICryptoTransform transform = symm.CreateEncryptor();
CryptoStream cstream = new CryptoStream(fsOut,transform,
ryptoStreamMode.Write);
BinaryReader br = new BinaryReader(fsIn);
//  Read the source file to cryptostream
cstream.Write(br.ReadBytes((int)fsIn.Length),0,(int)fsIn.Length);
cstream.FlushFinalBlock();
cstream.Close();
fsIn.Close();
fsOut.Close();
Console.WriteLine("created encrypted file {0}", tempfile);
Console.WriteLine("will now decrypt and show contents");
//  The inverse -- Decrypt a temporary file that was just encrypted 
fsIn = File.Open(tempfile,FileMode.Open,FileAccess.Read);
transform = symm.CreateDecryptor();
cstream = new CryptoStream(fsIn,transform,
CryptoStreamMode.Read);
StreamReader sr = new StreamReader(cstream);
Console.WriteLine("decrypted file text: " + sr.ReadToEnd());
fsIn.Close();
}
}
}

Encrypted network data

If I have a document that I only want to see for myself, I will not simply send it to you via ES69en-ES70en. I'm going to encrypt it using a symmetric algorithm; If someone intercepts it, they cannot read the document because they do not have the only key for encryption. But you don't have a key. I need to give you the key in some way so that you can decrypt the document, but not at the risk of the key and document being intercepted.

Asymmetric algorithms are one solution. The two keys used by such algorithms have the following relationship: information encrypted with the public key can only be decrypted with the corresponding private key. Therefore, I first ask you to send me your public key. Someone might intercept it on the way to me, but it doesn't matter, because they can only use the key to encrypt your message. I use your public key to encrypt the document and send it to you. You decrypt the document using a private key, which is the only key that can be decrypted, and is not delivered over the network.

Asymmetric algorithms are more expensive and slower than symmetric algorithms. So we don't want to use asymmetric algorithms to encrypt all the information in an online conversation. Instead, we use a symmetric algorithm. In the following example we use asymmetric encryption to encrypt the symmetric key. And then it encrypts using symmetric algorithms. This is actually how the security Interface layer (SSL) sets up a secure conversation between the server and the browser.
The example is an TCP program, divided into a server side and a client side. The workflow on the server side is as follows:

Receive the public key from the client.

Use the public key to encrypt future symmetric keys.

Sends the encrypted symmetric key to the client.

Sends information encrypted with the symmetric key to the client.

The code is as follows:


namespace com.billdawson.crypto
{
public class CryptoServer
{
private const int RSA_KEY_SIZE_BITS = 1024;
private const int RSA_KEY_SIZE_BYTES = 252;
private const int TDES_KEY_SIZE_BITS = 192;
public static void Main(string[] args)
{
int port;
string msg;
TcpListener listener;
TcpClient client;
SymmetricAlgorithm symm;
RSACryptoServiceProvider rsa;
// Access to the port 
try
{
port = Int32.Parse(args[0]);
msg = args[1];
}
catch
{
Console.WriteLine(USAGE);
return;
}
// Set up to monitor 
try
{
listener = new TcpListener(port);
listener.Start();
Console.WriteLine("Listening on port {0}",port);
client = listener.AcceptTcpClient();
Console.WriteLine("connection.");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
return;
}
try
{
rsa = new RSACryptoServiceProvider();
rsa.KeySize = RSA_KEY_SIZE_BITS;
//  Gets the client public key 
rsa.ImportParameters(getClientPublicKey(client));
symm = new TripleDESCryptoServiceProvider();
symm.KeySize = TDES_KEY_SIZE_BITS;
// Use the client's public key to encrypt the symmetric key and send it to the client. 
encryptAndSendSymmetricKey(client, rsa, symm);
// The message is encrypted and sent using a symmetric key 
encryptAndSendSecretMessage(client, symm, msg);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
finally
{
try
{
client.Close();
listener.Stop();
}
catch
{
// error 
}
Console.WriteLine("Server exiting");
}
}
private static RSAParameters getClientPublicKey(TcpClient client)
{
//  Gets the serialized public key from the byte stream and writes to the instance of the class by string and conversion 
byte[] buffer = new byte[RSA_KEY_SIZE_BYTES];
NetworkStream ns = client.GetStream();
MemoryStream ms = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
RSAParameters result;
int len = 0;
int totalLen = 0;
while(totalLen
(len = ns.Read(buffer,0,buffer.Length))>0)
{
totalLen+=len;
ms.Write(buffer, 0, len);
}
ms.Position=0;
result = (RSAParameters)bf.Deserialize(ms);
ms.Close();
return result;
}
private static void encryptAndSendSymmetricKey(
TcpClient client,
RSACryptoServiceProvider rsa,
SymmetricAlgorithm symm)
{
//  Use the client's public key to encrypt the symmetric key 
byte[] symKeyEncrypted;
byte[] symIVEncrypted;
NetworkStream ns = client.GetStream();
symKeyEncrypted = rsa.Encrypt(symm.Key, false);
symIVEncrypted = rsa.Encrypt(symm.IV, false);
ns.Write(symKeyEncrypted, 0, symKeyEncrypted.Length);
ns.Write(symIVEncrypted, 0, symIVEncrypted.Length);
}
private static void encryptAndSendSecretMessage(TcpClient client,
SymmetricAlgorithm symm,
string secretMsg)
{
//  The symmetric key and initialization vector encryption information are sent to the client 
byte[] msgAsBytes;
NetworkStream ns = client.GetStream();
ICryptoTransform transform =
symm.CreateEncryptor(symm.Key,symm.IV);
CryptoStream cstream =
new CryptoStream(ns, transform, CryptoStreamMode.Write);
msgAsBytes = Encoding.ASCII.GetBytes(secretMsg);
cstream.Write(msgAsBytes, 0, msgAsBytes.Length);
cstream.FlushFinalBlock();
}
}

The workflow of the client is:

Creates and sends the public key to the server.

Receive the encrypted symmetric key from the server.

Decrypt the symmetric key and treat it as a private asymmetric key.

Receive and decrypt information using asymmetric keys.

The code is as follows:


namespace com.billdawson.crypto
{
public class CryptoClient
{
private const int RSA_KEY_SIZE_BITS = 1024;
private const int RSA_KEY_SIZE_BYTES = 252;
private const int TDES_KEY_SIZE_BITS = 192;
private const int TDES_KEY_SIZE_BYTES = 128;
private const int TDES_IV_SIZE_BYTES = 128;
public static void Main(string[] args)
{
int port;
string host;
TcpClient client;
SymmetricAlgorithm symm;
RSACryptoServiceProvider rsa;
if (args.Length!=2)
{
Console.WriteLine(USAGE);
return;
}
try
{
host = args[0];
port = Int32.Parse(args[1]);
}
catch
{
Console.WriteLine(USAGE);
return;
}
try // The connection 
{
client = new TcpClient();
client.Connect(host,port);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
Console.Write(e.StackTrace);
return;
}
try
{
Console.WriteLine("Connected. Sending public key.");
rsa = new RSACryptoServiceProvider();
rsa.KeySize = RSA_KEY_SIZE_BITS;
sendPublicKey(rsa.ExportParameters(false),client);
symm = new TripleDESCryptoServiceProvider();
symm.KeySize = TDES_KEY_SIZE_BITS;
MemoryStream ms = getRestOfMessage(client);
extractSymmetricKeyInfo(rsa, symm, ms);
showSecretMessage(symm, ms);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
Console.Write(e.StackTrace);
}
finally
{
try
{
client.Close();
}
catch { // error 
}
}
}
private static void sendPublicKey(
RSAParameters key,
TcpClient client)
{
NetworkStream ns = client.GetStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(ns,key);
}
private static MemoryStream getRestOfMessage(TcpClient client)
{
// Get symmetric encryption keys, initialize vectors, secret information. Symmetric keys are used in common RSA The key 
// Encryption. Secret information is encrypted with a symmetric key 
MemoryStream ms = new MemoryStream();
NetworkStream ns = client.GetStream();
byte[] buffer = new byte[1024];
int len=0;
//  will NetStream  Writes data to the memory stream 
while((len = ns.Read(buffer, 0, buffer.Length))>0)
{
ms.Write(buffer, 0, len);
}
ms.Position = 0;
return ms;
}
private static void extractSymmetricKeyInfo(
RSACryptoServiceProvider rsa,
SymmetricAlgorithm symm,
MemoryStream msOrig)
{
MemoryStream ms = new MemoryStream();
//  To obtain TDES The key -- It is a public RSA Key encryption, decryption using private key 
byte[] buffer = new byte[TDES_KEY_SIZE_BYTES];
msOrig.Read(buffer,0,buffer.Length);
symm.Key = rsa.Decrypt(buffer,false);
//  To obtain TDES Initializing vector 
buffer = new byte[TDES_IV_SIZE_BYTES];
msOrig.Read(buffer, 0, buffer.Length);
symm.IV = rsa.Decrypt(buffer,false);
}
private static void showSecretMessage(
SymmetricAlgorithm symm,
MemoryStream msOrig)
{
// All data in the memory stream is encrypted 
byte[] buffer = new byte[1024];
int len = msOrig.Read(buffer,0,buffer.Length);
MemoryStream ms = new MemoryStream();
ICryptoTransform transform =
symm.CreateDecryptor(symm.Key,symm.IV);
CryptoStream cstream =new CryptoStream(ms, transform,
CryptoStreamMode.Write);
cstream.Write(buffer, 0, len);
cstream.FlushFinalBlock();
//  The memory stream is now decrypted information, in the form of bytes, converting it to a string 
ms.Position = 0;
len = ms.Read(buffer,0,(int) ms.Length);
ms.Close();
string msg = Encoding.ASCII.GetString(buffer,0,len);
Console.WriteLine("The host sent me this secret message:");
Console.WriteLine(msg);
}
}
}

Symmetric algorithms are appropriate when encrypting local data. While keeping the code generic, we have a variety of algorithms to choose from, and the algorithm USES the transform object to encrypt the data when it passes through a particular CryptoStream. When data needs to be sent over the network, the symmetric key is first encrypted using the received public asymmetric key.

This article covers only one part of the services of the ES109en.Security.Cryptography namespace. Although the article guarantees that only a private key can decrypt the information encrypted by the corresponding public key, it does not guarantee who sent the public key and the sender may be false. Classes that handle digital certificates are needed to address this risk.


Related articles: