Mã hóa aes phía máy khách javascript

AES là viết tắt của Advanced Encryption Standard và nó là một thuật toán mã hóa đối xứng. Nhiều lần chúng tôi yêu cầu mã hóa một số văn bản thuần túy như mật khẩu ở phía máy khách (Javascript) và gửi nó đến máy chủ và sau đó máy chủ giải mã nó để xử lý tiếp

Mã hóa aes phía máy khách javascript
Bồ tát Srivastava

24 tháng 4 năm 2022 - 13. 52 Cập nhật. Ngày 24 tháng 4 năm 2022 - 13. 55

0 2411

  • Facebook
  • Twitter

Mã hóa aes phía máy khách javascript

Xin chào, trong bài đăng này, chúng ta sẽ tìm hiểu cách triển khai mã hóa và giải mã AES bằng Java và JavaScript

Nhiều lần chúng tôi yêu cầu mã hóa một số văn bản thuần túy như mật khẩu ở phía máy khách (Javascript) và gửi nó đến máy chủ và sau đó máy chủ giải mã nó để xử lý tiếp hoặc ngược lại

AES là gì?

Thuật toán AES là một mật mã khối khóa đối xứng, lặp, hỗ trợ các khóa mật mã (khóa bí mật) 128, 192 và 256 bit để mã hóa và giải mã dữ liệu trong các khối 128 bit

Nếu dữ liệu được mã hóa không đáp ứng yêu cầu về kích thước khối là 128 bit, dữ liệu đó phải được đệm. Đệm là quá trình lấp đầy khối cuối cùng thành 128 bit

Biến thể AES

Thuật toán AES có sáu chế độ hoạt động

  1. ECB (Sách mã điện tử)
  2. CBC (Chuỗi khối mật mã)
  3. CFB (Phản hồi mật mã)
  4. OFB (Phản hồi đầu ra)
  5. TLB (Bộ đếm)
  6. GCM (Chế độ Galois/Bộ đếm)

Chúng ta có thể áp dụng phương thức hoạt động để tăng cường tác dụng của thuật toán mã hóa. Hơn nữa, chế độ hoạt động có thể chuyển đổi mật mã khối thành mật mã dòng. Mỗi chế độ đều có điểm mạnh và điểm yếu

Ở đây chúng ta sẽ chỉ thảo luận về CBC (Cipher Block Chaining)

CBC (Chuỗi khối mật mã)

Chế độ CBC sử dụng   Vectơ khởi tạo   (IV) . Đầu tiên, CBC sử dụng xor khối văn bản gốc với IV. Sau đó, nó mã hóa kết quả thành khối bản mã. Trong khối tiếp theo, nó sử dụng kết quả mã hóa để xor với khối văn bản gốc cho đến khối cuối cùng.

Trong chế độ này, mã hóa không thể được song song hóa, nhưng việc giải mã có thể được thực hiện song song. Nó cũng yêu cầu dữ liệu đệm

Kích thước của dữ liệu sau khi mã hóa

AES có kích thước khối là 128 bit hoặc 16 byte. AES không thay đổi kích thước và kích thước bản mã bằng với kích thước bản rõ. Ngoài ra, ở chế độ ECB và CBC, chúng ta nên sử dụng thuật toán đệm như   PKCS5.   Vậy kích thước của dữ liệu sau khi mã hóa là.

ciphertext_size (bytes) = cleartext_size + (16 - (cleartext_size % 16))

Để lưu trữ IV với bản mã, chúng tôi cần thêm 16 byte nữa

Thông số AES

Trong thuật toán AES, chúng ta cần ba tham số. dữ liệu đầu vào, khóa bí mật và IV. IV không được sử dụng trong chế độ ECB

Dữ liệu đầu vào

Dữ liệu đầu vào cho AES có thể là chuỗi, tệp, đối tượng và dựa trên mật khẩu

Chìa khoá bí mật

Có hai cách để tạo khóa bí mật trong AES. tạo từ một số ngẫu nhiên hoặc xuất phát từ một mật khẩu nhất định

Trong cách tiếp cận đầu tiên, khóa bí mật phải được tạo từ Trình tạo số ngẫu nhiên (giả) an toàn bằng mật mã như lớp SecureRandom

Trong cách tiếp cận thứ hai, khóa bí mật AES có thể được lấy từ một mật khẩu đã cho bằng chức năng dẫn xuất khóa dựa trên mật khẩu như PBKDF2. Chúng tôi cũng cần một giá trị muối để biến mật khẩu thành khóa bí mật. Muối cũng là một giá trị ngẫu nhiên

Chúng ta có thể sử dụng lớp SecretKeyFactory với thuật toán PBKDF2WithHmacSHA256 để tạo khóa từ một mật khẩu đã cho

private SecretKey generateKey(String salt, String passPhrase) throws NoSuchAlgorithmException, InvalidKeySpecException {
	SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
	KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), fromHex(salt), 1989, 256);
	return new SecretKeySpec(secretKeyFactory.generateSecret(keySpec).getEncoded(), "AES");
}

Vector khởi tạo (IV)

IV là một giá trị giả ngẫu nhiên và có cùng kích thước với khối được mã hóa. Chúng ta có thể sử dụng lớp SecureRandom để tạo IV ngẫu nhiên

public static IvParameterSpec generateIv() {
    byte[] iv = new byte[16];
    new SecureRandom().nextBytes(iv);
    return new IvParameterSpec(iv);
}

Mã hóa và giải mã

Sợi dây

Để thực hiện mã hóa chuỗi đầu vào, trước tiên chúng ta cần tạo khóa bí mật và IV theo phần trước. Bước tiếp theo, chúng ta tạo một thể hiện từ lớp

private SecretKey generateKey(String salt, String passPhrase) throws NoSuchAlgorithmException, InvalidKeySpecException {
	SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
	KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), fromHex(salt), 1989, 256);
	return new SecretKeySpec(secretKeyFactory.generateSecret(keySpec).getEncoded(), "AES");
}
0 bằng cách sử dụng phương thức
private SecretKey generateKey(String salt, String passPhrase) throws NoSuchAlgorithmException, InvalidKeySpecException {
	SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
	KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), fromHex(salt), 1989, 256);
	return new SecretKeySpec(secretKeyFactory.generateSecret(keySpec).getEncoded(), "AES");
}
1

Ngoài ra, chúng tôi định cấu hình phiên bản mật mã bằng phương thức

private SecretKey generateKey(String salt, String passPhrase) throws NoSuchAlgorithmException, InvalidKeySpecException {
	SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
	KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), fromHex(salt), 1989, 256);
	return new SecretKeySpec(secretKeyFactory.generateSecret(keySpec).getEncoded(), "AES");
}
2 với khóa bí mật, IV và chế độ mã hóa. Cuối cùng, chúng tôi mã hóa chuỗi đầu vào bằng cách gọi phương thức
private SecretKey generateKey(String salt, String passPhrase) throws NoSuchAlgorithmException, InvalidKeySpecException {
	SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
	KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), fromHex(salt), 1989, 256);
	return new SecretKeySpec(secretKeyFactory.generateSecret(keySpec).getEncoded(), "AES");
}
3. Phương thức này nhận byte đầu vào và trả về bản mã theo byte

public static String encrypt(String algorithm, String input, SecretKey key,
    IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException,
    InvalidAlgorithmParameterException, InvalidKeyException,
    BadPaddingException, IllegalBlockSizeException {
    
    Cipher cipher = Cipher.getInstance(algorithm);
    cipher.init(Cipher.ENCRYPT_MODE, key, iv);
    byte[] cipherText = cipher.doFinal(input.getBytes());
    return Base64.getEncoder()
        .encodeToString(cipherText);
}

Để giải mã một chuỗi đầu vào, chúng ta có thể khởi tạo mật mã của mình bằng cách sử dụng DECRYPT_MODE để giải mã nội dung

________số 8_______

Đây là mã hoàn chỉnh để mã hóa và giải mã AES bằng Java

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Objects;

/**
 * Encryption and Decryption using AES 256 Algorithm
 *
 */
public class AESUtil {

    public enum DataType {
        HEX,
        BASE64
    }

    private static final Logger LOGGER = LogManager.getLogger(AESUtil.class);

    private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
    private static final String SECRET_KEY_ALGORITHM = "PBKDF2WithHmacSHA1";
    private static final String KEY_ALGORITHM = "AES";

    private final int IV_SIZE = 128;

    private int iterationCount = 1989;
    private int keySize = 256;

    private int saltLength;

    private final DataType dataType = DataType.BASE64;

    private Cipher cipher;

    public AESUtil() {
        try {
            cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            saltLength = this.keySize / 4;
        } catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
            LOGGER.info(e.getMessage());
        }
    }

    public AESUtil(int keySize, int iterationCount) {
        this.keySize = keySize;
        this.iterationCount = iterationCount;
        try {
            cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            saltLength = this.keySize / 4;
        } catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
            LOGGER.info(e.getMessage());
        }
    }

    public String encrypt(String salt, String iv, String passPhrase, String plainText) {
        try {
            SecretKey secretKey = generateKey(salt, passPhrase);
            byte[] encrypted = doFinal(Cipher.ENCRYPT_MODE, secretKey, iv, plainText.getBytes(StandardCharsets.UTF_8));
            String cipherText;

            if (dataType.equals(DataType.HEX)) {
                cipherText = toHex(encrypted);
            } else {
                cipherText = toBase64(encrypted);
            }
            return cipherText;
        } catch (Exception e) {
            return null;
        }
    }

    public String encrypt(String passPhrase, String plainText) {
        try {
            String salt = toHex(generateRandom(keySize / 8));
            String iv = toHex(generateRandom(IV_SIZE / 8));
            String cipherText = encrypt(salt, iv, passPhrase, plainText);
            return salt + iv + cipherText;
        } catch (Exception e) {
            return null;
        }
    }

    public String decrypt(String salt, String iv, String passPhrase, String cipherText) {
        try {
            SecretKey key = generateKey(salt, passPhrase);
            byte[] encrypted;
            if (dataType.equals(DataType.HEX)) {
                encrypted = fromHex(cipherText);
            } else {
                encrypted = fromBase64(cipherText);
            }
            byte[] decrypted = doFinal(Cipher.DECRYPT_MODE, key, iv, encrypted);
            return new String(Objects.requireNonNull(decrypted), StandardCharsets.UTF_8);
        } catch (Exception e) {
            return null;
        }
    }

    public String decrypt(String passPhrase, String cipherText) {
        try {
            String salt = cipherText.substring(0, saltLength);
            int ivLength = IV_SIZE / 4;
            String iv = cipherText.substring(saltLength, saltLength + ivLength);
            String ct = cipherText.substring(saltLength + ivLength);
            return decrypt(salt, iv, passPhrase, ct);
        } catch (Exception e) {
            return null;
        }
    }

    private SecretKey generateKey(String salt, String passPhrase) {
        try {
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(SECRET_KEY_ALGORITHM);
            KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), fromHex(salt), iterationCount, keySize);
            return new SecretKeySpec(secretKeyFactory.generateSecret(keySpec).getEncoded(), KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            LOGGER.info(e.getMessage());
        }
        return null;
    }

    private static byte[] fromBase64(String str) {
        return DatatypeConverter.parseBase64Binary(str);
    }

    private static String toBase64(byte[] ba) {
        return DatatypeConverter.printBase64Binary(ba);
    }

    private static byte[] fromHex(String str) {
        return DatatypeConverter.parseHexBinary(str);
    }

    private static String toHex(byte[] ba) {
        return DatatypeConverter.printHexBinary(ba);
    }

    private byte[] doFinal(int mode, SecretKey secretKey, String iv, byte[] bytes) {
        try {
            cipher.init(mode, secretKey, new IvParameterSpec(fromHex(iv)));
            return cipher.doFinal(bytes);
        } catch (InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException
                | InvalidKeyException e) {
            LOGGER.info(e.getMessage());
        }
        return null;
    }

    private static byte[] generateRandom(int length) {
        SecureRandom random = new SecureRandom();
        byte[] randomBytes = new byte[length];
        random.nextBytes(randomBytes);
        return randomBytes;
    }

}

Đây là mã hoàn chỉnh để mã hóa và giải mã AES bằng JavaScript và CryptoJS

let CryptoJS = require("crypto-js");

export class AESUtil {

  constructor() {
    this._keySize = 256;
    this._ivSize = 128;
    this._iterationCount = 1989;
  }

  get keySize() {
    return this._keySize;
  }

  set keySize(value) {
    this._keySize = value;
  }

  get iterationCount() {
    return this._iterationCount;
  }

  set iterationCount(value) {
    this._iterationCount = value;
  }

  generateKey(salt, passPhrase) {
    return CryptoJS.PBKDF2(passPhrase, CryptoJS.enc.Hex.parse(salt), {
      keySize: this.keySize / 32,
      iterations: this._iterationCount
    })
  }

  encryptWithIvSalt(salt, iv, passPhrase, plainText) {
    let key = this.generateKey(salt, passPhrase);
    let encrypted = CryptoJS.AES.encrypt(plainText, key, {
      iv: CryptoJS.enc.Hex.parse(iv)
    });
    return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
  }

  decryptWithIvSalt(salt, iv, passPhrase, cipherText) {
    let key = this.generateKey(salt, passPhrase);
    let cipherParams = CryptoJS.lib.CipherParams.create({
      ciphertext: CryptoJS.enc.Base64.parse(cipherText)
    });
    let decrypted = CryptoJS.AES.decrypt(cipherParams, key, {
      iv: CryptoJS.enc.Hex.parse(iv)
    });
    return decrypted.toString(CryptoJS.enc.Utf8);
  }

  encrypt(passPhrase, plainText) {
    let iv = CryptoJS.lib.WordArray.random(this._ivSize / 8).toString(CryptoJS.enc.Hex);
    let salt = CryptoJS.lib.WordArray.random(this.keySize / 8).toString(CryptoJS.enc.Hex);
    let ciphertext = this.encryptWithIvSalt(salt, iv, passPhrase, plainText);
    return salt + iv + ciphertext;
  }

  decrypt(passPhrase, cipherText) {
    let ivLength = this._ivSize / 4;
    let saltLength = this.keySize / 4;
    let salt = cipherText.substr(0, saltLength);
    let iv = cipherText.substr(saltLength, ivLength);
    let encrypted = cipherText.substring(ivLength + saltLength);
    return this.decryptWithIvSalt(salt, iv, passPhrase, encrypted);
  }
}

export const aesUtil = new AESUtil();

Bây giờ bạn có thể sử dụng điều này để mã hóa dữ liệu từ phía máy khách và giải mã dữ liệu ở phía máy chủ hoặc ngược lại với việc sử dụng cùng một khóa bí mật

AES trong máy khách là gì

Mã hóa và giải mã AES là kỹ thuật bảo mật cao và nhanh nhất. Mã hóa phía máy khách là phương pháp hiệu quả để cung cấp bảo mật cho việc truyền dữ liệu và dữ liệu được lưu trữ . Bài báo này đề xuất xác thực người dùng để bảo mật dữ liệu của thuật toán mã hóa trong điện toán đám mây.

Mã hóa AES trong javascript và giải mã trong C# là gì?

Tiêu chuẩn mã hóa nâng cao (AES) là một thuật toán mã hóa đối xứng . Thuật toán được phát triển bởi hai nhà mật mã người Bỉ Joan Daemen và Vincent Rijmen. AES được thiết kế để hoạt động hiệu quả trong cả phần cứng và phần mềm và hỗ trợ độ dài khối 128 bit và độ dài khóa 128, 192 và 256 bit.

Mã hóa AES trong javascript và giải mã trong Java là gì?

AES là viết tắt của Advanced Encryption Standard và nó là một thuật toán mã hóa đối xứng. Nhiều lần chúng tôi yêu cầu mã hóa một số văn bản thuần túy như mật khẩu ở phía máy khách (Javascript) và gửi nó đến máy chủ, sau đó máy chủ giải mã nó để xử lý thêm.

AES có thể bị bẻ khóa không?

AES chưa bao giờ bị bẻ khóa và an toàn trước mọi cuộc tấn công vũ phu trái với niềm tin và lập luận. Tuy nhiên, kích thước khóa được sử dụng để mã hóa phải luôn đủ lớn để các máy tính hiện đại không thể bẻ khóa mặc dù đã xem xét những tiến bộ về tốc độ của bộ xử lý dựa trên định luật Moore.