The differences between symmetric encryption and asymmetric encryption are mainly as follows:
-
1. Use of keys: In symmetric encryption, encryption and decryption use the same key, while asymmetric encryption uses two different keys. Generally
Use the public key to encrypt and the private key to decrypt.
-
2. Speed and efficiency: Symmetric encryption and decryption are relatively fast, suitable for long-term use of data, rather than the time spent on asymmetric encryption and decryption.
Long and relatively slow, and is only suitable for use of small amounts of data.
-
3. Security: The security of symmetric encryption is relatively low because both parties use the same secret key. If one party’s secret key is leaked, then the entire one is
Communication will be cracked. Asymmetric encryption uses a pair of secret keys, one for encryption and the other for decryption, and the public key is public and the private key is self-contained.
The keys that are saved do not need to be synchronized before communication like symmetric encryption, so their security is better.
-
4. Key distribution: In symmetric encryption, it is necessary to securely share the key between the two parties in the communication. If there is no secure channel to share the key, it may
It will be intercepted by hackers, resulting in data breach. Asymmetric encryption does not require sharing the key before communication, so it is more secure.
In practical applications, symmetric encryption and asymmetric encryption are often used in combination to give full play to their respective advantages. For example, symmetric encryption can be used to add
A large amount of data is then used to securely distribute the symmetrically encrypted keys.
1. Symmetric encryption
1.1 AES
package main import ( "bytes" "crypto/aes" "crypto/cipher" "encoding/base64" "fmt" ) // AES encryptionfunc main() { // AES encryption takes up 16, 24 or 32 bytes key := "12345678abcdefgh" // Encrypted string str := "hello world!" ("Stand before encryption:", str) cipherText, _ := SCEncryptString(str, key) ("Encrypted string:", cipherText) originalText, _ := SCDecryptString(cipherText, key) ("Decrypted string:", originalText) } // Symmetric encryptionfunc SCEncrypt(originalBytes, key []byte) ([]byte, error) { // 1. Instantiate the password block (parameter is the key) block, err := (key) if err != nil { return nil, err } blockSize := () // 2. Fill in plain text (the parameters are the number of blocks of the original byte slice and password object) paddingBytes := PKCS5Padding(originalBytes, blockSize) // 3. Instantiated encryption mode (parameters are password objects and keys) blockMode := (block, key[:blockSize]) // 4. Encrypt the plaintext after the byte is filled (the parameters are encrypted byte slices and filled byte slices) cipherBytes := make([]byte, len(paddingBytes)) (cipherBytes, paddingBytes) return cipherBytes, nil } // Symmetric decryptionfunc SCDecrypt(cipherBytes, key []byte) ([]byte, error) { // 1. Instantiate the password block (parameter is the key) block, err := (key) if err != nil { return nil, err } blockSize := () // 2. Instant decryption mode (parameters are password objects and keys) blockMode := (block, key[:blockSize]) // 3. Decrypt the ciphertext (the parameters are padded byte slices and encrypted byte slices) paddingBytes := make([]byte, len(cipherBytes)) (paddingBytes, cipherBytes) // 4. Remove the padded bytes (the parameter is padded slice) originalBytes := PKCS5UnPadding(paddingBytes) return originalBytes, nil } // Encapsulated string symmetric encryptionfunc SCEncryptString(originalText, key string) (string, error) { cipherBytes, err := SCEncrypt([]byte(originalText), []byte(key)) if err != nil { return "", err } // base64 encoding (encoded) base64str := (cipherBytes) return base64str, nil } // Encapsulated string symmetric decryptionfunc SCDecryptString(cipherText, key string) (string, error) { // base64 decode (decode) cipherBytes, _ := (cipherText) cipherBytes, err := SCDecrypt(cipherBytes, []byte(key)) if err != nil { return "", err } return string(cipherBytes), nil } // The end is filled with bytesfunc PKCS5Padding(data []byte, blockSize int) []byte { // The values and numbers to be filled padding := blockSize - len(data)%blockSize // Single binary value to fill slice1 := []byte{byte(padding)} // Binary array to be filled slice2 := (slice1, padding) //Fill to the end of the data return append(data, slice2...) } // Fill in the end with 0func ZerosPadding(data []byte, blockSize int) []byte { // The number of fills padding := blockSize - len(data)%blockSize // Single 0 data to be filled slice1 := []byte{0} // 0 binary array to fill slice2 := (slice1, padding) //Fill to the end of the data return append(data, slice2...) } // Remove the padded bytesfunc PKCS5UnPadding(data []byte) []byte { // Get the last numeric value of the binary array unpadding := data[len(data)-1] // Valid data between the start of intercepting and total length minus the padding value result := data[:(len(data) - int(unpadding))] return result } // Remove the filled 0func ZerosUnPadding(data []byte) []byte { // Remove sub-slices that meet the conditions return (data, func(r rune) bool { return r == 0 }) }
package main import ( "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/base64" "fmt" "io" ) // AES encryption// AES encryption takes up 16, 24 or 32 bytesvar encryptionKey = []byte("12345678abcdefgh") func encrypt(data []byte) (string, error) { block, err := (encryptionKey) if err != nil { return "", err } ciphertext := make([]byte, +len(data)) iv := ciphertext[:] if _, err := (, iv); err != nil { return "", err } stream := (block, iv) (ciphertext[:], data) return (ciphertext), nil } func decrypt(encodedData string) ([]byte, error) { ciphertext, err := (encodedData) if err != nil { return nil, err } block, err := (encryptionKey) if err != nil { return nil, err } if len(ciphertext) < { return nil, ("Invalid encrypted data length") } iv := ciphertext[:] ciphertext = ciphertext[:] stream := (block, iv) (ciphertext, ciphertext) return ciphertext, nil } func main() { data := []byte("Hello World!") encryptedData, err := encrypt(data) if err != nil { ("Encryption failed:", err) return } ("Encrypted data:", encryptedData) decryptedData, err := decrypt(encryptedData) if err != nil { ("Decryption failed:", err) return } ("Decrypted data:", string(decryptedData)) }
1.2 DES
package main import ( "bytes" "crypto/cipher" "crypto/des" "encoding/base64" "fmt" ) // DES encryptionfunc main() { // DES key occupies 8 bytes key := "1234abcd" // Encrypted string str := "hello world!" ("Stand before encryption:", str) cipherText, _ := SCEncryptString(str, key) ("Encrypted string:", cipherText) originalText, _ := SCDecryptString(cipherText, key) ("Decrypted string:", originalText) } // Symmetric encryptionfunc SCEncrypt(originalBytes, key []byte) ([]byte, error) { // 1. Instantiate the password block (parameter is the key) block, err := (key) if err != nil { return nil, err } blockSize := () // 2. Fill in plain text (the parameters are the number of blocks of the original byte slice and password object) paddingBytes := PKCS5Padding(originalBytes, blockSize) // 3. Instantiated encryption mode (parameters are password objects and keys) blockMode := (block, key[:blockSize]) // 4. Encrypt the plaintext after the byte is filled (the parameters are encrypted byte slices and filled byte slices) cipherBytes := make([]byte, len(paddingBytes)) (cipherBytes, paddingBytes) return cipherBytes, nil } // Symmetric decryptionfunc SCDecrypt(cipherBytes, key []byte) ([]byte, error) { // 1. Instantiate the password block (parameter is the key) block, err := (key) if err != nil { return nil, err } blockSize := () // 2. Instant decryption mode (parameters are password objects and keys) blockMode := (block, key[:blockSize]) // 3. Decrypt the ciphertext (the parameters are padded byte slices and encrypted byte slices) paddingBytes := make([]byte, len(cipherBytes)) (paddingBytes, cipherBytes) // 4. Remove the padded bytes (the parameter is padded slice) originalBytes := PKCS5UnPadding(paddingBytes) return originalBytes, nil } // Encapsulated string symmetric encryptionfunc SCEncryptString(originalText, key string) (string, error) { cipherBytes, err := SCEncrypt([]byte(originalText), []byte(key)) if err != nil { return "", err } // base64 encoding (encoded) base64str := (cipherBytes) return base64str, nil } // Encapsulated string symmetric decryptionfunc SCDecryptString(cipherText, key string) (string, error) { // base64 decode (decode) cipherBytes, _ := (cipherText) cipherBytes, err := SCDecrypt(cipherBytes, []byte(key)) if err != nil { return "", err } return string(cipherBytes), nil } // The end is filled with bytesfunc PKCS5Padding(data []byte, blockSize int) []byte { // The values and numbers to be filled padding := blockSize - len(data)%blockSize // Single binary value to fill slice1 := []byte{byte(padding)} // Binary array to be filled slice2 := (slice1, padding) //Fill to the end of the data return append(data, slice2...) } // Fill in the end with 0func ZerosPadding(data []byte, blockSize int) []byte { // The number of fills padding := blockSize - len(data)%blockSize // Single 0 data to be filled slice1 := []byte{0} // 0 binary array to fill slice2 := (slice1, padding) //Fill to the end of the data return append(data, slice2...) } // Remove the padded bytesfunc PKCS5UnPadding(data []byte) []byte { // Get the last numeric value of the binary array unpadding := data[len(data)-1] // Valid data between the start of intercepting and total length minus the padding value result := data[:(len(data) - int(unpadding))] return result } // Remove the filled 0func ZerosUnPadding(data []byte) []byte { // Remove sub-slices that meet the conditions return (data, func(r rune) bool { return r == 0 }) }
package main import ( "crypto/cipher" "crypto/des" "crypto/rand" "encoding/base64" "fmt" "io" ) // DES encryption// DES key occupies 8 bytesvar encryptionKey = []byte("1234abcd") func encrypt(data []byte) (string, error) { block, err := (encryptionKey) if err != nil { return "", err } ciphertext := make([]byte, +len(data)) iv := ciphertext[:] if _, err := (, iv); err != nil { return "", err } stream := (block, iv) (ciphertext[:], data) return (ciphertext), nil } func decrypt(encodedData string) ([]byte, error) { ciphertext, err := (encodedData) if err != nil { return nil, err } block, err := (encryptionKey) if err != nil { return nil, err } if len(ciphertext) < { return nil, ("Invalid encrypted data length") } iv := ciphertext[:] ciphertext = ciphertext[:] stream := (block, iv) (ciphertext, ciphertext) return ciphertext, nil } func main() { data := []byte("Hello") encryptedData, err := encrypt(data) if err != nil { ("Encryption failed:", err) return } ("Encrypted data:", encryptedData) decryptedData, err := decrypt(encryptedData) if err != nil { ("Decryption failed:", err) return } ("Decrypted data:", string(decryptedData)) }
1.3 3DES
package main import ( "bytes" "crypto/cipher" "crypto/des" "encoding/base64" "fmt" ) // 3DES encryptionfunc main() { // 3DES key occupies 24 bytes key := "abcdefghijklmn0123456789" // Encrypted string str := "hello world!" ("Stand before encryption:", str) cipherText, _ := SCEncryptString(str, key) ("Encrypted string:", cipherText) originalText, _ := SCDecryptString("3eS626HB2R9ZGcOAYLuWCw==", key) ("Decrypted string:", originalText) } // Symmetric encryptionfunc SCEncrypt(originalBytes, key []byte) ([]byte, error) { // 1. Instantiate the password block (parameter is the key) block, err := (key) if err != nil { return nil, err } blockSize := () // 2. Fill in plain text (the parameters are the number of blocks of the original byte slice and password object) paddingBytes := PKCS5Padding(originalBytes, blockSize) // 3. Instantiated encryption mode (parameters are password objects and keys) blockMode := (block, key[:blockSize]) // 4. Encrypt the plaintext after the byte is filled (the parameters are encrypted byte slices and filled byte slices) cipherBytes := make([]byte, len(paddingBytes)) (cipherBytes, paddingBytes) return cipherBytes, nil } // Symmetric decryptionfunc SCDecrypt(cipherBytes, key []byte) ([]byte, error) { // 1. Instantiate the password block (parameter is the key) block, err := (key) if err != nil { return nil, err } blockSize := () // 2. Instant decryption mode (parameters are password objects and keys) blockMode := (block, key[:blockSize]) // 3. Decrypt the ciphertext (the parameters are padded byte slices and encrypted byte slices) paddingBytes := make([]byte, len(cipherBytes)) (paddingBytes, cipherBytes) // 4. Remove the padded bytes (the parameter is padded slice) originalBytes := PKCS5UnPadding(paddingBytes) return originalBytes, nil } // Encapsulated string symmetric encryptionfunc SCEncryptString(originalText, key string) (string, error) { cipherBytes, err := SCEncrypt([]byte(originalText), []byte(key)) if err != nil { return "", err } // base64 encoding (encoded) base64str := (cipherBytes) return base64str, nil } // Encapsulated string symmetric decryptionfunc SCDecryptString(cipherText, key string) (string, error) { // base64 decode (decode) cipherBytes, _ := (cipherText) cipherBytes, err := SCDecrypt(cipherBytes, []byte(key)) if err != nil { return "", err } return string(cipherBytes), nil } // The end is filled with bytesfunc PKCS5Padding(data []byte, blockSize int) []byte { // The values and numbers to be filled padding := blockSize - len(data)%blockSize // Single binary value to fill slice1 := []byte{byte(padding)} // Binary array to be filled slice2 := (slice1, padding) //Fill to the end of the data return append(data, slice2...) } // Fill in the end with 0func ZerosPadding(data []byte, blockSize int) []byte { // The number of fills padding := blockSize - len(data)%blockSize // Single 0 data to be filled slice1 := []byte{0} // 0 binary array to fill slice2 := (slice1, padding) //Fill to the end of the data return append(data, slice2...) } // Remove the padded bytesfunc PKCS5UnPadding(data []byte) []byte { // Get the last numeric value of the binary array unpadding := data[len(data)-1] // Valid data between the start of intercepting and total length minus the padding value result := data[:(len(data) - int(unpadding))] return result } // Remove the filled 0func ZerosUnPadding(data []byte) []byte { // Remove sub-slices that meet the conditions return (data, func(r rune) bool { return r == 0 }) }
package main import ( "crypto/cipher" "crypto/des" "crypto/rand" "encoding/base64" "fmt" "io" ) // 3DES encryption// 3DES key occupies 24 bytesvar encryptionKey = []byte("abcdefghijklmn0123456789") func encrypt(data []byte) (string, error) { block, err := (encryptionKey) if err != nil { return "", err } ciphertext := make([]byte, +len(data)) iv := ciphertext[:] if _, err := (, iv); err != nil { return "", err } stream := (block, iv) (ciphertext[:], data) return (ciphertext), nil } func decrypt(encodedData string) ([]byte, error) { ciphertext, err := (encodedData) if err != nil { return nil, err } block, err := (encryptionKey) if err != nil { return nil, err } if len(ciphertext) < { return nil, ("Invalid encrypted data length") } iv := ciphertext[:] ciphertext = ciphertext[:] stream := (block, iv) (ciphertext, ciphertext) return ciphertext, nil } func main() { data := []byte("Hello") encryptedData, err := encrypt(data) if err != nil { ("Encryption failed:", err) return } ("Encrypted data:", encryptedData) decryptedData, err := decrypt(encryptedData) if err != nil { ("Decryption failed:", err) return } ("Decrypted data:", string(decryptedData)) }
2. Asymmetric encryption algorithm RSA
2.1 Generate a key pair
Generate key pairs and store them in the public key file () and the private key file ().
package main import ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/pem" "log" "os" ) func main() { if err := GenerateRSAKey(); err != nil { ("Key generation failed!") } ("The key was generated successfully!") } // Generate key pair and save to filefunc GenerateRSAKey() error { // 1. The core steps for RSA to generate private key files // 1) Generate RSA key pair // The key length, the default value is 1024 bits bits := 1024 privateKer, err := (, bits) if err != nil { return err } // 2) Convert the private key object into DER encoding form derPrivateKer := x509.MarshalPKCS1PrivateKey(privateKer) // 3), create a private key pem file file, err := ("../certs/") if err != nil { return err } // 4) Encode the key information and write it to the private key file block := &{ Type: "RSA PRIVATE KEY", Bytes: derPrivateKer, } err = (file, block) if err != nil { return err } // 2. The core steps of RSA to generate public key files // 1) Generate public key object publicKey := & // 2) Serialize the public key object into DER encoding format derPublicKey, err := (publicKey) if err != nil { return err } // 3), create a public key pem file file, err = ("../certs/") if err != nil { return err } // 4) Encode the public key information and write it to the public key file block = &{ Type: "PUBLIC KEY", Bytes: derPublicKey, } err = (file, block) if err != nil { return err } return nil }
2.2 RSA encryption and decryption process
Public key encryption, private key decryption.
Encryption process:
- 1. Read the public key file and parse the public key object
- 2. Encrypt plaintext using public key
Decryption process:
- 1. Read the private key file and parse the public key object
- 2. Use the private key to decrypt the ciphertext
package main import ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/base64" "encoding/pem" "errors" "fmt" "io/ioutil" ) func main() { str := "Hello World!" encryptstr, _ := RSAEncryptString(str, "../certs/") (encryptstr) decrypt, _ := RSADecryptString(encryptstr, "../certs/") (decrypt) } // RSA encrypts byte array, returns byte arrayfunc RSAEncrypt(originalBytes []byte, filename string) ([]byte, error) { // 1. Read the public key file and parse the public key object publicKey, err := ReadParsePublicKey(filename) if err != nil { return nil, err } // 2. RSA encryption, parameters are random numbers, public key objects, bytes that need to be encrypted // Reader is a powerful pseudo-random generator for globally shared password security return rsa.EncryptPKCS1v15(, publicKey, originalBytes) } // RSA decrypts the byte array and returns the byte arrayfunc RSADecrypt(cipherBytes []byte, filename string) ([]byte, error) { // 1. Read the private key file and parse the private key object privateKey, err := ReadParsePrivaterKey(filename) if err != nil { return nil, err } // 2. Ras decryption, parameters are random numbers, private key objects, bytes that need to be decrypted return rsa.DecryptPKCS1v15(, privateKey, cipherBytes) } // Read the public key file and parse the public key objectfunc ReadParsePublicKey(filename string) (*, error) { // 1. Read the public key file and obtain the public key bytes publicKeyBytes, err := (filename) if err != nil { return nil, err } // 2. Decode the public key bytes and generate the encrypted block object block, _ := (publicKeyBytes) if block == nil { return nil, ("Public key information error!") } // 3. Analyze the DER encoded public key and generate the public key interface publicKeyInterface, err := () if err != nil { return nil, err } // 4. Transform the public key interface into a public key object publicKey := publicKeyInterface.(*) return publicKey, nil } // Read the private key file and parse the private key objectfunc ReadParsePrivaterKey(filename string) (*, error) { // 1. Read the private key file and obtain the private key bytes privateKeyBytes, err := (filename) if err != nil { return nil, err } // 2. Encode the private key file and generate an encrypted block object block, _ := (privateKeyBytes) if block == nil { return nil, ("Private key information is incorrect!") } // 3. Parse the DER encoded private key and generate the private key object privateKey, err := x509.ParsePKCS1PrivateKey() if err != nil { return nil, err } return privateKey, nil } // RSA encrypted string, return the string processed by base64func RSAEncryptString(originalText, filename string) (string, error) { cipherBytes, err := RSAEncrypt([]byte(originalText), filename) if err != nil { return "", err } return (cipherBytes), nil } // RSA decrypts the encrypted string processed by base64 and returns the plain text before encryptionfunc RSADecryptString(cipherlText, filename string) (string, error) { cipherBytes, _ := (cipherlText) originalBytes, err := RSADecrypt(cipherBytes, filename) if err != nil { return "", err } return string(originalBytes), nil }
2.3 Digital signature verification
The difference between encryption and signature:
- Encryption: public key encryption, private key decryption
- Signature: Private key signature, public key verification
Digital signature process:
- The hash value of the original text is signed with your own private key, and the original text + signature is given to the other party. When the other party uses the public key to verify the signature, it is compared with the original hash.
Encrypt and sign:
-
The original text is encrypted with the other party's public key, the original text hash value is signed with your own private key, and the ciphertext + signature is signed with the other party. The other party's public key verifies the signature and solves the private key
Comparison of hash values of secret text.
package main import ( "crypto" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/base64" "encoding/pem" "errors" "fmt" "io/ioutil" ) func main() { str := "Hello World!" base64Sig, _ := RSASign([]byte(str), "../certs/") ("Signed information:", base64Sig) err := RSAVerify([]byte(str), base64Sig, "../certs/") if err == nil { ("Verification was successful!") } else { ("Verification failed!") } } // Private key signing processfunc RSASign(data []byte, filename string) (string, error) { // 1. Select the hash algorithm to hash the data that needs to be signed myhash := crypto.SHA256 hashInstance := () (data) hashed := (nil) // 2. Read the private key file and parse the private key object privateKey, err := ReadParsePrivaterKey(filename) if err != nil { return "", err } // 3. RSA digital signature (parameters are random numbers, private key objects, hash types, and hash strings for signature files), generating base64-encoded signature string bytes, err := rsa.SignPKCS1v15(, privateKey, myhash, hashed) if err != nil { return "", err } return (bytes), nil } // Public key verification signature processfunc RSAVerify(data []byte, base64Sig, filename string) error { // 1. Decode the signature content encoded by base64 and return the signature section bytes, err := (base64Sig) if err != nil { return err } // 2. Select the hash algorithm to hash the data that needs to be signed myhash := crypto.SHA256 hashInstance := () (data) hashed := (nil) // 3. Read the public key file and parse the public key object publicKey, err := ReadParsePublicKey(filename) if err != nil { return err } // 4. RSA verification digital signature (parameters are public key object, hash type, hash string of the signature file, and signed bytes) return rsa.VerifyPKCS1v15(publicKey, myhash, hashed, bytes) } // Read the public key file and parse the public key objectfunc ReadParsePublicKey(filename string) (*, error) { // 1. Read the public key file and obtain the public key bytes publicKeyBytes, err := (filename) if err != nil { return nil, err } // 2. Decode the public key bytes and generate the encrypted block object block, _ := (publicKeyBytes) if block == nil { return nil, ("Public key information error!") } // 3. Analyze the DER encoded public key and generate the public key interface publicKeyInterface, err := () if err != nil { return nil, err } // 4. Transform the public key interface into a public key object publicKey := publicKeyInterface.(*) return publicKey, nil } // Read the private key file and parse the private key objectfunc ReadParsePrivaterKey(filename string) (*, error) { // 1. Read the private key file and obtain the private key bytes privateKeyBytes, err := (filename) if err != nil { return nil, err } // 2. Encode the private key file and generate an encrypted block object block, _ := (privateKeyBytes) if block == nil { return nil, ("Private key information is incorrect!") } // 3. Parse the DER encoded private key and generate the private key object privateKey, err := x509.ParsePKCS1PrivateKey() if err != nil { return nil, err } return privateKey, nil }
This is the article about the example code for Go to implement symmetric encryption and asymmetric encryption. For more related Go languages, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!