Python đọc tệp pem

Trong mật mã khóa công khai, còn được gọi là mật mã bất đối xứng, cơ chế mã hóa dựa trên hai khóa liên quan, khóa công khai và khóa riêng. Khóa chung được sử dụng để mã hóa tin nhắn, trong khi chỉ chủ sở hữu khóa riêng mới có thể giải mã tin nhắn.  

Trong hướng dẫn này, chúng ta sẽ tìm hiểu cách đọc khóa chung và khóa riêng từ tệp PEM

Đầu tiên, chúng ta sẽ nghiên cứu một số khái niệm quan trọng xung quanh mật mã khóa công khai. Sau đó, chúng ta sẽ học cách đọc các tệp PEM bằng Java thuần túy

Cuối cùng, chúng ta sẽ khám phá thư viện BouncyCastle như một cách tiếp cận khác

2. Các khái niệm

Trước khi bắt đầu, hãy thảo luận về một số khái niệm chính

X. 509 là một tiêu chuẩn xác định định dạng của chứng chỉ khóa công khai. Vì vậy, định dạng này mô tả khóa chung, cùng với các thông tin khác.

DER là định dạng mã hóa phổ biến nhất để lưu trữ dữ liệu, như X. 509 và khóa riêng PKCS8 trong tệp. Đó là mã hóa nhị phân và không thể xem nội dung kết quả bằng trình soạn thảo văn bản.

PKCS8 là cú pháp tiêu chuẩn để lưu trữ thông tin khóa cá nhân. Khóa riêng có thể được mã hóa tùy chọn bằng thuật toán đối xứng.

Không chỉ khóa riêng RSA có thể được xử lý theo tiêu chuẩn này mà còn cả các thuật toán khác. Khóa riêng PKCS8 thường được trao đổi thông qua định dạng mã hóa PEM.

PEM là cơ chế mã hóa cơ sở 64 của chứng chỉ DER. PEM cũng có thể mã hóa các loại dữ liệu khác, chẳng hạn như khóa công khai/riêng tư và yêu cầu chứng chỉ.

Tệp PEM cũng chứa đầu trang và chân trang mô tả loại dữ liệu được mã hóa

-----BEGIN PUBLIC KEY-----
...Base64 encoding of the DER encoded certificate...
-----END PUBLIC KEY-----

3. Sử dụng Java thuần túy

3. 1. Đọc dữ liệu PEM từ một tệp

Hãy bắt đầu bằng cách đọc tệp PEM và lưu trữ nội dung của nó thành một chuỗi

String key = new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());

3. 2. Nhận khóa công khai từ chuỗi PEM

Bây giờ chúng ta sẽ xây dựng một phương thức tiện ích lấy khóa chung từ chuỗi được mã hóa PEM

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjtGIk8SxD+OEiBpP2/T
JUAF0upwuKGMk6wH8Rwov88VvzJrVm2NCticTk5FUg+UG5r8JArrV4tJPRHQyvqK
wF4NiksuvOjv3HyIf4oaOhZjT8hDne1Bfv+cFqZJ61Gk0MjANh/T5q9vxER/7TdU
NHKpoRV+NVlKN5bEU/NQ5FQjVXicfswxh6Y6fl2PIFqT2CfjD+FkBPU1iT9qyJYH
A38IRvwNtcitFgCeZwdGPoxiPPh1WHY8VxpUVBv/2JsUtrB/rAIbGqZoxAIWvijJ
Pe9o1TY3VlOzk9ASZ1AeatvOir+iDVJ5OpKmLnzc46QgGPUsjIyo6Sje9dxpGtoG
QQIDAQAB
-----END PUBLIC KEY-----

Giả sử chúng ta nhận được một Tệp dưới dạng tham số

public static RSAPublicKey readPublicKey(File file) throws Exception {
    String key = new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());

    String publicKeyPEM = key
      .replace("-----BEGIN PUBLIC KEY-----", "")
      .replaceAll(System.lineSeparator(), "")
      .replace("-----END PUBLIC KEY-----", "");

    byte[] encoded = Base64.decodeBase64(publicKeyPEM);

    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
    return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}

Như chúng ta có thể thấy, trước tiên chúng ta cần xóa đầu trang, chân trang và cả các dòng mới. Sau đó, chúng ta cần giải mã chuỗi được mã hóa Base64 thành định dạng nhị phân tương ứng.  

Tiếp theo, chúng ta cần tải kết quả vào một lớp đặc tả khóa có thể xử lý tài liệu khóa công khai. Trong trường hợp này, chúng tôi sẽ sử dụng lớp X509EncodedKeySpec.

Cuối cùng, chúng ta có thể tạo một đối tượng khóa công khai từ đặc tả bằng cách sử dụng lớp KeyFactory .

3. 3. Nhận khóa riêng từ chuỗi PEM

Bây giờ chúng ta đã biết cách đọc khóa chung, thuật toán để đọc khóa riêng cũng rất giống nhau.  

Chúng tôi sẽ sử dụng khóa riêng được mã hóa PEM ở định dạng PKCS8. Hãy xem đầu trang và chân trang trông như thế nào

-----BEGIN PRIVATE KEY-----
...Base64 encoded key...
-----END PRIVATE KEY-----

Như chúng ta đã biết trước đây, chúng ta cần một lớp có thể xử lý tài liệu chính PKCS8. Lớp PKCS8EncodedKeySpec đảm nhận vai trò đó.

Vì vậy, hãy xem thuật toán

public RSAPrivateKey readPrivateKey(File file) throws Exception {
    String key = new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());

    String privateKeyPEM = key
      .replace("-----BEGIN PRIVATE KEY-----", "")
      .replaceAll(System.lineSeparator(), "")
      .replace("-----END PRIVATE KEY-----", "");

    byte[] encoded = Base64.decodeBase64(privateKeyPEM);

    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
    return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}

4. Sử dụng thư viện BouncyCastle

4. 1. Đọc khóa công khai

Chúng ta sẽ khám phá thư viện BouncyCastle và xem cách chúng ta có thể sử dụng nó như một giải pháp thay thế cho việc triển khai Java thuần túy

Hãy lấy khóa công khai

public RSAPublicKey readPublicKey(File file) throws Exception {
    KeyFactory factory = KeyFactory.getInstance("RSA");

    try (FileReader keyReader = new FileReader(file);
      PemReader pemReader = new PemReader(keyReader)) {

        PemObject pemObject = pemReader.readPemObject();
        byte[] content = pemObject.getContent();
        X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
        return (RSAPublicKey) factory.generatePublic(pubKeySpec);
    }
}

Có một vài lớp quan trọng mà chúng ta cần lưu ý khi sử dụng BouncyCastle

  • PemReader – lấy Reader làm tham số và phân tích nội dung của nó. Nó loại bỏ các tiêu đề không cần thiết và giải mã dữ liệu Base64 PEM cơ bản thành định dạng nhị phân.
  • PemObject – lưu trữ kết quả do PemReader tạo ra

Hãy xem một cách tiếp cận khác bao bọc các lớp của Java (X509EncodedKeySpec, KeyFactory) thành lớp riêng của BouncyCastle (JcaPEMKeyConverter)

public RSAPublicKey readPublicKeySecondApproach(File file) throws IOException {
    try (FileReader keyReader = new FileReader(file)) {
        PEMParser pemParser = new PEMParser(keyReader);
        JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
        SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance(pemParser.readObject());
        return (RSAPublicKey) converter.getPublicKey(publicKeyInfo);
    }
}

4. 2. Đọc khóa riêng

Bây giờ chúng ta sẽ xem hai ví dụ rất giống với những ví dụ được hiển thị ở trên

Trong ví dụ đầu tiên, chúng ta chỉ cần thay thế lớp X509EncodedKeySpec bằng lớp PKCS8EncodedKeySpec và trả về một đối tượng RSAPrivateKey thay vì một RSAPublicKey

________số 8

Bây giờ, hãy làm lại cách tiếp cận thứ hai từ phần trước một chút để đọc khóa riêng

public RSAPrivateKey readPrivateKeySecondApproach(File file) throws IOException {
    try (FileReader keyReader = new FileReader(file)) {

        PEMParser pemParser = new PEMParser(keyReader);
        JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
        PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.getInstance(pemParser.readObject());

        return (RSAPrivateKey) converter.getPrivateKey(privateKeyInfo);
    }
}

Như có thể thấy, chúng tôi vừa thay thế SubjectPublicKeyInfo bằng PrivateKeyInfo và RSAPublicKey bằng RSAPrivateKey

4. 3. Thuận lợi

Có một số lợi thế được cung cấp bởi thư viện BouncyCastle

Một lợi thế là chúng ta không cần bỏ qua hoặc xóa thủ công đầu trang và chân trang. Một điều nữa là chúng tôi cũng không chịu trách nhiệm giải mã Base64. Do đó, chúng ta có thể viết mã ít bị lỗi hơn với BouncyCastle

Hơn nữa, thư viện BouncyCastle cũng hỗ trợ định dạng PKCS1. Mặc dù thực tế là PKCS1 cũng là một định dạng phổ biến được sử dụng để lưu trữ các khóa mật mã (chỉ các khóa RSA), Java không hỗ trợ riêng nó

5. Phần kết luận

Trong bài viết này, chúng tôi đã học cách đọc khóa chung và khóa riêng từ tệp PEM

Đầu tiên, chúng tôi đã nghiên cứu một số khái niệm chính xung quanh mật mã khóa công khai. Sau đó, chúng tôi đã xem cách đọc khóa công khai và khóa riêng bằng Java thuần túy

Cuối cùng, chúng tôi đã khám phá thư viện BouncyCastle và phát hiện ra đây là một giải pháp thay thế tốt, vì nó cung cấp một số lợi thế so với triển khai Java thuần túy

Làm cách nào để tải tệp PEM bằng Python?

With pem, your Python application can cope with all of those scenarios: >>> import pem >>> certs = pem. parse_file("chain. pem") >>> certs [, ] >>> str(certs[0]) '-----BEGIN CERTIFICATE-----\n...'

Python đọc certs từ đâu?

Theo mặc định, mô-đun ssl của Python sử dụng gói chứng chỉ CA hệ thống - /etc/pki/tls/certs/ca-bundle .

Trình phân tích cú pháp pem là gì?

Phân tách các tệp Chứng chỉ CA chứa nhiều PEM thành một mảng PEM . Điều này hữu ích khi bạn chuyển các tệp Chứng chỉ CA chứa nhiều PEM vào tls.

Tệp PEM là gì?

Tệp Thư nâng cao bảo mật (PEM) là các vùng chứa chứng chỉ nối nhau thường được sử dụng trong quá trình cài đặt chứng chỉ khi nhiều chứng chỉ tạo thành một chuỗi hoàn chỉnh đang được nhập dưới dạng một tệp duy nhất. They are a defined standard in RFCs 1421 through 1424.