HTTPS algorithm combat

Interview build rocket to work screw, everyone is good I am iron egg son, insist on progress a little bit every day.

Read a lot of HTTPS articles feel are in the popular science principle, most are very detailed, but the implementation of very few, all have this article.

If you are not familiar with the BASIC friends of HTTP, please go to SITE B :HTTP Basics, this big guy’s article is very detailed for beginners.

HTTP is not safe

The HTTP protocol to express transport protocol, the interaction process and data transmission is encrypted, communication both sides also does not have any certification, communication process is very vulnerable to hijacking, to monitor, tampered with, severe cases, the cause of malicious traffic hijacked, even cause personal privacy leak (such as bank card card number and password leak) such as a serious security problem.

HTTP communication can be compared to sending A letter. A sends A letter to B. In the process of sending the letter, it passes through the hands of many postmen who can open the letter and read the contents (because HTTP is sent in plain text). Anything in A’s letters, including various accounts and passwords, would be easily stolen. In addition, postmen can also forge or modify the contents of the letter, so that the contents of the letter B receives are false.

For example, in the process of HTTP communication, “middleman” embeds advertising links in the HTTP packets sent by the server to the user, resulting in many bad links on the user interface. Or modify the user’s request header URL, so that the user’s request is hijacked to another site, and the user’s request never reaches the real server. These will lead to users not getting the right service, or even a heavy loss.

HTTP uses symmetric encryption for data transmission, which can be simulated in the following two ways:

1. Implementation of JS simulation

// The encryption key and the decryption key are the same (secret)

let secret = 3

/ / encryption
function encrypt(message) {
  let buffer = Buffer.from(message)
  for (let i = 0; i < buffer.length; i++) {
    buffer[i] = buffer[i] + secret
  }
  return buffer.toString()
}
/ / decryption
function decrypt(message) {
  let buffer = Buffer.from(message)
  for (let i = 0; i < buffer.length; i++) {
    buffer[i] = buffer[i] - secret
  }
  return buffer.toString()
}

let message = 'abc'
let encryptMessage = encrypt(message)
console.log('encryptMessagen', encryptMessage)

let decryptMessage = decrypt(encryptMessage)
console.log('decryptMessagen', decryptMessage)

Copy the code

2. Crypto module to achieve simulation

const crypto = require('crypto');

/ / encryption
const encrypt = (password, string) = > {
  // The symmetric encryption algorithm used is AES-192-Cbc
  const algorithm = 'aes-192-cbc';
  Salt is used to generate the key. 24 specifies the length of the key to be 24 bits
  const key = crypto.scryptSync(password, 'salt'.24);
  console.log('key:', key); // => key: 
      
  console.log('Key length:${key.length}`); // => The length of the key is 24

  // Initialize the vector
  const iv = Buffer.alloc(16.0);
  // Obtain the Cipher encryption class
  const cipher = crypto.createCipheriv(algorithm, key, iv);

  // utF-8 specifies the character encoding of the data to be encrypted, hex specifies the character encoding of the output
  let encryptedString = cipher.update(string, 'utf8'.'hex');

  encryptedString += cipher.final('hex');

  return encryptedString;
};

const PASSWORD = 'lyreal666';
const encryptedString = encrypt(PASSWORD, 'Make a little progress every day');
console.log('The encrypted data is:${encryptedString}`); // => The encrypted data is XXXX

/ / decryption
const decrypt = (password, encryptedString) = > {
  const algorithm = 'aes-192-cbc';
  // Use the same algorithm to generate the same secret key
  const key = crypto.scryptSync(password, 'salt'.24);
  const iv = Buffer.alloc(16.0);
  // Generate the Decipher class
  const decipher = crypto.createDecipheriv(algorithm, key, iv);

  let decryptedString = decipher.update(encryptedString, 'hex'.'utf8');
  decryptedString += decipher.final('utf8');

  return decryptedString;
};

const decryptedString = decrypt(PASSWORD, encryptedString);
console.log('When decrypted data:${decryptedString}`); // => When decrypting data: make a little progress every day
Copy the code

Summary: Advantages and disadvantages

Advantages:

  1. Small computation, fast encryption speed, high encryption efficiency.

Disadvantages:

  1. Both sides of the transaction use the same key, the security can not be guaranteed;

  2. Use symmetric encryption every time

How to achieve HTTPS security

HTTPS implements data encryption security through the following three points:

  1. Asymmetric encryption algorithms (public and private keys) exchange symmetric keys
  2. Digital certificate authentication (verify whether the public key is forged)
  3. Use symmetric keys to encrypt and decrypt subsequent data

Asymmetric encryption implementation

Asymmetric encryption uses a pair of secret keys, called a public key and a private key, also called an asymmetric secret key.

Encryption is only one password, why do you need two passwords for the whole asymmetric encryption?

In fact, as long as the length of the encrypted password is long enough, the encrypted data is generally safe when the password itself is not available. But there is a problem in the practical application of network data such as encryption, because use the same secret key encryption and decryption, so the server and the client is necessarily to the exchange of the secret key, but it is because the symmetrical secret key with a secret key exchange this process may be an intermediary to steal the secret key, once the symmetrical secret key stolen, and by analyzing the encryption algorithm, Then the data being transmitted is transparent to the middleman. So the fatal disadvantage of symmetric encryption is that it cannot guarantee the security of the secret key.

So does asymmetric encryption guarantee the security of the key? Yes, a secret key can be boldly disclosed, and the disclosed secret key is called a public key. The secret key of asymmetric encryption is calculated by the encryption algorithm and is paired. The secret key that can be disclosed is called the public key and the private key that cannot be disclosed is called the private key.

Asymmetric encryption means that the encryption and decryption parties use different keys. One is used as the public key, which can be disclosed, and the other is used as the private key, which cannot be disclosed. Only the private key can decrypt the ciphertext encrypted by the public key, and only the public key can decrypt the contents encrypted by the private key.

1. Js mode to achieve asymmetric encryption algorithm

// Euler function
let p = 3, q = 11
let N = p * q; / / 33
let fN = (p - 1) * (q - 1)
let e = 7 // Pick a random exponent e
// {e,N} {7,33} makes our public key. The public key can be issued to anyone. It is public
// The public key and the key are a pair. The data encrypted by the public key must be decrypted with the public key
// We can deduce the private key from the public key, but only if you know fN
// e*d % fN ! ==1 means that's the key we're looking for
for (var d = 1; e * d % fN ! = =1; d++) {
  d++;
}

console.log(d) // d=3

let data = 5
let c = Math.pow(data, e) % N;
console.log('c', c)

let original = Math.pow(c, d) % N;
console.log(original)
Copy the code

2. The crypto module simulates asymmetric encryption

let { generateKeyPairSync, privateEncrypt, publicDecrypt } = require('crypto')

// Generate a pair of key pairs, one public key and one private key
let rsa = generateKeyPairSync('rsa', {
  modulusLength: 1024.publicKeyEncoding: {
    type: 'spki'.format: 'pem' // Private key in base64 format
  },
  privateKeyEncoding: {
    type: 'pkcs8'.format: 'pem'.cipher: 'aes-256-cbc'.passphrase: 'passphrase'}})let message = 'Front end iron egg'
/ / encryption
let encryptMessage = privateEncrypt({
  key: rsa.privateKey,
  passphrase: 'passphrase',
}, Buffer.from(message, 'utf8'))
console.log('encryptMessage', encryptMessage)

/ / decryption
let decryptMessage = publicDecrypt(rsa.publicKey, encryptMessage)
console.log('decryptMessage', decryptMessage.toString())
Copy the code

Summary: Advantages and disadvantages

Asymmetric encryption is more secure than symmetric encryption, but it has two fatal disadvantages:

  1. CPU computing resources are very high. In a complete TLS handshake, the computation amount of asymmetric decryption during key exchange accounts for more than 90% of the whole handshake process. The computational amount of symmetric encryption is only 0.1% of that of asymmetric encryption. If asymmetric encryption and decryption are used in the subsequent data transmission at the application layer, the CPU performance cost is too large for the server to bear. Simentec’s experimental data shows that the asymmetric algorithm consumes 1000 times more CPU resources than the symmetric algorithm to encrypt and decrypt the same number of files.

  2. The asymmetric encryption algorithm has a limit on the length of the encrypted content, which cannot exceed the length of the public key. For example, the common public key length is 2048 bits, which means that the content to be encrypted cannot exceed 256 bytes.

Therefore, asymmetric encryption and decryption (which consumes extremely CPU resources) can only be used for symmetric key exchange or CA signature, and is not suitable for encryption and decryption of application-layer content transmission.

Digital Certificate Signature

If you use asymmetric encryption, the client needs to have the public key to begin with, or it won’t be able to encrypt.

How can clients A and B get their public keys safely?

  1. The server sends the public key to each client

  2. The server puts the public key on a remote server where the client can request it

Choose option 1 because option 2 has one more request and has to deal with the placement of the public key.

What if the public key is switched? Another chicken-and-balls problem?

However, there is a problem with scheme 1: what if the server sends the public key to the client, but the middleman switches it?

Answer: Use a third party’s public key to solve the chicken-and-egg problem

The problem with the public key being switched arises because the client cannot tell whether the person returning the public key is a middleman or a real server. This is actually the authentication problem in cryptography.

The difficulty of the problem is that if you choose to transfer the public key directly to the client, the problem that the public key is transferred by the middleman can not be solved.

Therefore, we cannot directly pass the public key of the server to the client. Instead, a third party uses its private key to encrypt our public key and then sends it to the client. The client uses the public key of the third party to decrypt the data.

1. Digital signature algorithm simulation implementation

let crypto = require('crypto')
let content = '12334561111111111'
 / / 32 bits
let md5Hash = crypto.createHash('md5').digest('hex')
console.log('md5Hash', md5Hash, md5Hash.length)
/ / 64
let salt = '1';
let sha1Hash = crypto.createHmac('sha256', salt).digest('hex')
console.log('sha1Hash', sha1Hash, sha1Hash.length);

Copy the code

2. Complete certificate algorithm simulation implementation

// Implement the principle of certificate
let passphrase = 'passphrase'
let { generateKeyPairSync, createHash, createSign, createVerify, } = require('crypto')
// Generate a pair of key pairs, one public key and one private key
let serverRsa = generateKeyPairSync('rsa', {
  modulusLength: 1024.publicKeyEncoding: {
    type: 'spki'.format: 'pem' // Private key in base64 format
  },
  privateKeyEncoding: {
    type: 'pkcs8'.format: 'pem'.cipher: 'aes-256-cbc',
    passphrase// Private key password}})// Generate a pair of key pairs, one public key and one private key
let caRsa = generateKeyPairSync('rsa', {
  modulusLength: 1024.publicKeyEncoding: {
    type: 'spki'.format: 'pem' // Private key in base64 format
  },
  privateKeyEncoding: {
    type: 'pkcs8'.format: 'pem'.cipher: 'aes-256-cbc',
    passphrase// Private key password}})const info = {
  domain: 'http://127.0.0.1:8080'.publicKey: serverRsa.publicKey
}
// Send this application information to the CA to request a certificate
// The implementation of the signature is not the info but the hash because the signature algorithm is very poor and generally cannot calculate large amounts of data
let hash = createHash('sha256').update(JSON.stringify(info)).digest('hex')

let sign = getSign(hash, caRsa.privateKey, passphrase)

let valid = verifySign(hash, sign, caRsa.publicKey)
console.log('Browser validates CA signature', valid)

function getSign(content, privateKey, passphrase) {
  var siginObj = createSign('RSA-SHA256');
  siginObj.update(content);
  return siginObj.sign({
    key: privateKey,
    format: 'pem',
    passphrase
  }, 'hex')}function verifySign(content, sign, publicKey) {
  var verifyObj = createVerify('RSA-SHA256');
  verifyObj.update(content)
  return verifyObj.verify(publicKey, sign, 'hex')}Copy the code

Welcome friends to comment correction, work hard together progress, insist on a little progress every day.