Основы: подпись, шифрование, дайджест и сертификат java.security Framework

Java
Основы: подпись, шифрование, дайджест и сертификат java.security Framework

предисловие

При взаимодействии с внешним интерфейсом или подключении к сторонним продавцам личные данные необходимо шифровать. Одностороннее шифрование, симметричное шифрование и асимметричное шифрование, соответствующие алгоритмы также различны. Java предоставляет единую структуру для стандартизации (java.security) API для безопасного шифрования. Ниже будут представлены один за другим

  • Понятие и классификация алгоритма шифрования
  • генерация ключей
  • Инструмент алгоритма дайджеста — MessageDigest
  • Инструмент алгоритма подписи-Signature
  • Обычно используемые инструменты шифрования-Cipher
  • Сертификат - сохранение сертификатов
  • KeyStore — класс сущности для сертификатов ключей
  • загрузка https-сертификата

Подписывайтесь на официальный аккаунт и общайтесь вместе; поиск в WeChat: проскользнуть вперед

1 Понятие и классификация алгоритмов шифрования

Существует три типа широко используемых алгоритмов шифрования, а именно:

  • Одностороннее шифрование: то есть необратимое шифрование, такое как MD5, SHA, HMAC.
  • Симметричное шифрование: то есть стороны шифрования и дешифрования используют один и тот же ключ для шифрования и дешифрования данных, например DES, PBE и т. д.
  • Асимметричное шифрование: Асимметричное шифрование делится на открытый ключ и секретный ключ. Эти два асимметричны. Например, содержимое, зашифрованное с помощью закрытого ключа, необходимо расшифровать с помощью открытого ключа, а содержимое, зашифрованное с помощью открытого ключа, необходимо расшифровать. с закрытым ключом. DSA, RSA

2 генерация ключей

Генерация симметричных ключей шифрования

  • KeyGenerator используется для генерации симметричного ключа (обратимое шифрование) или криптографического ключа.
  • Поддерживаемые алгоритмы: AES, ARCFOUR, DES, DESede, HmacMD5, HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384, HmacSHA512, RC2.
public static final KeyGenerator getInstance(String algorithm, String provider)
public static final KeyGenerator getInstance(String algorithm)
public final void init(int keysize)
public final void init(int keysize, SecureRandom random)
public final void init(SecureRandom random)
public final void init(AlgorithmParameterSpec params, SecureRandom random)
public final SecretKey generateKey()
  • Пример
public static void main(String[] args) throws  Exception {
    SecretKey secretKey = generatorDesKey();
    System.out.println(secretKey);
}
public static SecretKey generatorDesKey() throws NoSuchAlgorithmException {
    KeyGenerator keyGen = KeyGenerator.getInstance("DES");
    SecureRandom random = new SecureRandom();
    random.nextBytes(new byte[128]);
    keyGen.init(56,random);
    SecretKey key = keyGen.generateKey();
    return key;
}
------------输出结果------------------
com.sun.crypto.provider.DESKey@185c3

Генерация асимметричных ключей шифрования

  • KeyPairGenerator используется для создания пары ключей KeyPair для алгоритмов асимметричного шифрования.KeyPair будет включать открытый ключ и закрытый ключ.
  • Поддерживаемые алгоритмы: DiffieHellman, DSA, RSA, RSASSA-PSS, EC
//KeyPairGenerator.java
public static KeyPairGenerator getInstance(String algorithm)
public static KeyPairGenerator getInstance(String algorithm, String provider)
public void initialize(int keysize, SecureRandom random)
public void initialize(AlgorithmParameterSpec params, SecureRandom random)
public final KeyPair genKeyPair() 
//KeyPair.java
public PublicKey getPublic()
public PrivateKey getPrivate()
  • Пример
public static void main(String[] args) throws Exception {
    KeyPair keyPair = generatorRsaKey();
    System.out.println(keyPair);
}
public static KeyPair generatorRsaKey() throws Exception {
    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
    SecureRandom random = new SecureRandom();
    random.nextBytes(new byte[516]);
    keyGen.initialize(516,random);
    KeyPair keyPair = keyGen.genKeyPair();
    System.out.println(keyPair.getPrivate());
    System.out.println(keyPair.getPublic());
    return keyPair;
}
  • выходной результат
SunRsaSign RSA private CRT key, 516 bits
  params: null
  modulus: 126519853979546358862851378153247782379894323767375778571361894186790679401365500006956495592162216057219204240578435837612184688685910973224797092901015673
  private exponent: 84346569319697572575234252102165188253262882511583852380907929457860452934243188047935652497010382336410866699832067872276413297543254894848799721123249067
Sun RSA public key, 516 bits
  params: null
  modulus: 126519853979546358862851378153247782379894323767375778571361894186790679401365500006956495592162216057219204240578435837612184688685910973224797092901015673
  public exponent: 3
java.security.KeyPair@5010be6

Взаимное преобразование ключа Key и спецификации ключа KeySpec

If the key is stored on a hardware device, its specification may contain information that helps identify the key on the device

KeySpec — это интерфейс, используемый для формирования (прозрачной) спецификации содержимого ключа ключа шифрования. Если ключ хранится на аппаратном устройстве, его спецификация может содержать информацию, помогающую идентифицировать ключ на этом устройстве.

  • KeySpec является нормативным, поэтому KeySpec обычно генерируется на основе внешних параметров, а затем на основе KeySpec генерируется соответствующий Key (личное понимание, если у вас есть какие-либо идеи, пожалуйста, выскажите свое мнение). Функция SecretKeyFactory и KeyFactory заключается в преобразовании Key и KeySpec

SecretKeyFactory: используется для преобразования между симметричными ключами шифрования и спецификациями ключей, используется с KeyGenerator.

  • Поддерживаемые алгоритмы: AES, ARCFOUR, DES, DESede, PBEWithMD5AndDES, PBEWithHmacSHA256AndAES_128, PBKDF2WithHmacSHA256.
public static final SecretKeyFactory getInstance(String algorithm)
public static final SecretKeyFactory getInstance(String algorithm, String provider)
public final SecretKey translateKey(SecretKey key)
public final SecretKey generateSecret(KeySpec keySpec)
public final KeySpec getKeySpec(SecretKey key, Class<?> keySpec)
  • Пример
public static void main(String[] args) throws Exception {
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
    byte[] DESKey = "helloWWW".getBytes(StandardCharsets.UTF_8);// 设置密钥
    DESKeySpec keySpec = new DESKeySpec(DESKey);// 设置密钥参数
    SecretKey key = keyFactory.generateSecret(keySpec);// 得到密钥对象
    System.out.println(key);
}
------------输出结果------------------
com.sun.crypto.provider.DESKey@18e49

KeyFactory: используется для преобразования между ключами асимметричного шифрования и спецификациями ключей, используется с KeyPairGenerator.

  • Поддерживаемые алгоритмы: DiffieHellman, DSA, RSA, RSASSA-PSS, EC
//KeyFactory.java
public static KeyFactory getInstance(String algorithm)
public static KeyFactory getInstance(String algorithm, String provider)
public final PublicKey generatePublic(KeySpec keySpec)
public final PrivateKey generatePrivate(KeySpec keySpec)
public final <T extends KeySpec> T getKeySpec(Key key, Class<T> keySpec)
  • Пример
public static void main(String[] args) throws Exception {
    //生成RSA秘钥对;generatorRsaKey是上面示例提供的函数
    KeyPair keyPair = generatorRsaKey();
    System.out.println(keyPair);
    //PublicKey转KeySpec;KeySpec再转PublicKey
    X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(keyPair.getPublic().getEncoded());
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
    System.out.println(pubKey);
    //PrivateKey转KeySpec;KeySpec再转PrivateKey
    PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(keyPair.getPrivate().getEncoded());
    PrivateKey priKey = keyFactory.generatePrivate(priKeySpec);
    System.out.println(priKey);
}
  • выходной результат
java.security.KeyPair@78e03bb5
Sun RSA public key, 1024 bits
  params: null
  modulus: 94134923375030889337699664145116176095803777687781162111756914700229869014912695784710407302811615186395818803402552376808400599961548587586207216709744471870318354813036696801675648731428269930963470277811176883827680414539855481218813862408748594430021606927061565116386180650249935749556615770533203721821
  public exponent: 65537
SunRsaSign RSA private CRT key, 1024 bits
  params: null
  modulus: 94134923375030889337699664145116176095803777687781162111756914700229869014912695784710407302811615186395818803402552376808400599961548587586207216709744471870318354813036696801675648731428269930963470277811176883827680414539855481218813862408748594430021606927061565116386180650249935749556615770533203721821
  private exponent: 67868152791098303572124282937222322055125020915630253288684471666171190487123683962152169691286583419399765605089805755591451063493647416931630849589322449230367252892862038338916192807582203337302166911147185956153147905653905702289234855039234840869874793012808454810161546053566242403672442319692325665473

3 алгоритма дайджеста — MessageDigest и javax.crypto.Mac (HMAC)

  • Одностороннее шифрование является необратимым. MD5, SHA и MAC являются алгоритмами одностороннего шифрования, также известными как алгоритмы дайджеста.
  • MD5 и SHA вычисляют дайджест фиксированной длины (хэш-значение) на основе открытого текста с использованием алгоритма хеширования, а затем отправляют открытый текст и дайджест получателю.Получатель вычисляет дайджест в соответствии с тем же алгоритмом и сравнивает два дайджеста одинаковы.Правильность открытого текста может быть проверена, и сценарии его применения: предотвращение подделки и проверка данных
  • Такие алгоритмы, как MD5 и SHA, имеют открытый исходный код и их легко тестировать. Существует ли более безопасный алгоритм дайджеста? HMAC - хеш-функция с ключом (паролем), которая принимает ключ и текстовое сообщение в качестве входных данных и создает дайджест сообщения. Ключ обычно создается с помощью KeyGenerator, что эквивалентно значению пароля, и вероятность его обнаружения невелика.
  • Алгоритмы, поддерживаемые MessageDigest: MD2, MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256.
  • Алгоритмы, поддерживаемые javax.crypto.Mac: HmacMD5, HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384, HmacSHA512, PBEWithHmacSHA1.
  • Пример MD5
MessageDigest digest = MessageDigest.getInstance("MD5");
System.out.println(new String(digest.digest("hello world!".getBytes())));
System.out.println(new String(digest.digest("hello world!".getBytes())));
------------输出结果------------------
0���G?�w
0���G?�w
  • Пример MAC-адреса
public static void main(String[] args) throws Exception {
    // 初始化HmacMD5摘要算法的密钥产生器
    KeyGenerator generator = KeyGenerator.getInstance("HmacMD5");
    // 产生密钥
    SecretKey secretKey = generator.generateKey();
    //SecretKeySpec继承于SecretKey和KeySpec,因此可直接用SecretKeySpec初始化Mac
    //SecretKey secretKey = new SecretKeySpec("password".getBytes(), "HmacMD5");
    Mac mac = Mac.getInstance("HmacMD5");
    mac.init(secretKey);
    //计算摘要
    String data = "hello world";
    byte[] result1 = mac.doFinal(data.getBytes());
    byte[] result2 = mac.doFinal(data.getBytes());
    System.out.println(new String(result1).equals(new String(result2)));
}
------------输出结果------------------    
true

4 Инструмент алгоритма подписи — Подпись

  • Алгоритм подписи на самом деле является алгоритмом шифрования.Зашифрованные данные однозначно идентифицируются, точно так же, как подпись человека может представлять личность человека. Подпись обычно относится к процессу шифрования открытого текста с помощью закрытого ключа алгоритма асимметричного шифрования.Сгенерированный зашифрованный текст может быть идентифицирован и расшифрован лицом, у которого есть открытый ключ.Пока ваш открытый ключ является точным и правильным, вы можете гарантировать что вы можете расшифровать его Данные от стороны, держащей закрытый ключ
  • Как убедиться, что открытый ключ правильный и не был подделан? 1: Индивидуально для вас, 2: После получения открытого ключа он будет сертифицирован авторитетной организацией Для соответствующего процесса, пожалуйста, обратитесь к статье, написанной ранее.Сеть: HTTPS-аутентификация, процесс шифрования интервью с другом
  • Поддерживаемые алгоритмы: NONEwithRSA, MD2withRSA, MD5withRSA, SHA512/224withRSA, SHA512/256withRSA, RSASSA-PSS, NONEwithDSA, SHA512withDSA, NONEwithECDSA, SHA512withECDSA, MD5withRSAandMGF1 (слишком много, выберите несколько)
  • Пример Signature.API, используемый с KeyPairGenerator
public static void main(String[] args) throws Exception {
    KeyPair keyPair = generatorRsaKey();
    Signature signature = Signature.getInstance("MD5withRSA");
    signature.initSign(keyPair.getPrivate());
    //加解密数据
    byte[] data = "hello world".getBytes();
    //数据签名
    signature.update(data);
    byte[] digest = signature.sign();
    //数据解密加验证
    signature.initVerify(keyPair.getPublic());
    signature.update(data);
    System.out.println("验证结果:"+signature.verify(digest));
}
------------输出结果------------------
验证结果:true

5 часто используемых инструментов шифрования — Cipher

  • Используется для шифрования/дешифрования данных. Поддерживаются различные типы алгоритмов: симметричное шифрование (например, AES), асимметричное шифрование (например, RSA).
  • Поддерживаемые алгоритмы: AES, AESWrap, ARCFOUR, Blowfish, DES, DESede, DESedeWrap, ECIES, RSA (слишком много, выберите несколько)
  • Пример
public static void main(String[] args) throws Exception {
    KeyPair keyPair = generatorRsaKey();
    Cipher cipher = Cipher.getInstance("RSA");
    // 编码前设定编码方式及密钥
    cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPrivate());
    //加解密数据
    byte[] data = "hello world".getBytes();
    //数据签名
    byte[] enData = cipher.doFinal(data);
    //数据解密
    cipher.init(Cipher.DECRYPT_MODE, keyPair.getPublic());
    byte[] newData = cipher.doFinal(enData);
    System.out.println("验证结果:"+new String(newData));
}
------------输出结果------------------
验证结果:hello world

6 Сертификат-магазин сертификатов

  • CertificateFactory: используется для создания сертификатов открытых ключей (Certificate) и списков отзыва сертификатов (CRL).
  • Сертификат и его подклассы X509Certificate
  • CertPath и CertPathBuilder: для создания цепочек сертификатов (также известных как пути сертификатов).
  • CertPathValidator: используется для проверки цепочки сертификатов.
  • CRL: Список отозванных сертификатов
  • CertStore: используется для хранения извлеченных сертификатов и CRL.
  • Пример CertificateFactory и Certificate
  • Пример
//certificateStream是证书的输入流
public static PublicKey getPublicKeyByCer(InputStream certificateStream) throws Exception{
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
    Certificate certificate = certificateFactory.generateCertificate(certificateStream);
    return certificate.getPublicKey();
}

7 KeyStore — класс сущности для сертификатов ключей

  • KeyStore используется для хранения закрытых ключей и сертификатов (открытый ключ находится в сертификате)
  • Открытый ключ: это цифровая ассоциация подробного объекта, и он должен быть известен всем другим объектам, которые хотят иметь доверительные отношения с этим объектом.Открытый ключ используется для проверки подписи;
  • Закрытый ключ: некоторое число, закрытый и открытый ключи хранятся в паре ключей всех систем, зашифрованных с помощью открытого ключа.Открытый ключ используется для шифрования данных, а закрытый ключ используется для вычисления подписи.Сообщения, зашифрованные с помощью открытый ключ может быть расшифрован только с помощью закрытого ключа. Сообщения, подписанные с помощью закрытого ключа, могут быть подписаны только с помощью открытого ключа.
  • Пример
public static void main(String[] args) throws Exception {
    InputStream certificateStream = null;
    //根据Certificate生成KeyStore
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    KeyStore keyStore = KeyStore.getInstance("PKCS12");
    keyStore.load(null);
    keyStore.setCertificateEntry("certificate", certificateFactory.generateCertificate(certificateStream));
    //加载jks文件,并生成KeyStore
    KeyStore trustKeyStore = KeyStore.getInstance("jks");
    FileInputStream trustKeyStoreFile = new FileInputStream("/root/trustKeyStore.jks");
    trustKeyStore.load(trustKeyStoreFile, "password".toCharArray());
}

8 java.https API для загрузки сертификатов

  • KeyManagerFactory, TrustManagerFactory => KeyManager, TrustManager => SSLContext => SSLEngine, SSLSocketFactory, SSLSocket

Общий процесс загрузки сертификата

  • Создание KeyManagerFactory и TrustManagerFactory с сертификатом, генерация KeyStore
  • KeyManagerFactory и TrustManagerFactory используются для создания KeyManager и TrustManager
  • И KeyManager и TrustManager используются для инициализации SSLContext.
  • Затем используйте SSLContext для создания объекта, который фактически реализует протокол SSL/TLS (SSLSocketFactory, SSLSocket или SSLEngine).
  • SSLSocket и SSLEngine могут использоваться непосредственно в коммуникационном объекте.
  • Роль KeyManager и TrustManager:
    • Диспетчер ключей отвечает за отображение используемых учетных данных (используемый стандарт шифрования, алгоритм шифрования, сертификат, открытый ключ, подпись и т. д.) узлу.
    • TrustManager отвечает за проверку учетных данных, полученных от однорангового узла.Существует несколько способов проверки учетных данных: один из них — создать объект CertPath и позволить встроенной инфраструктуре открытых ключей (PKI) JDK выполнить проверку. Внутри реализация CertPath может создать объект Signature и использовать его для проверки каждой подписи в цепочке сертификатов.
  • Пример: сгенерируйте SSLContext и инициализируйте apache-httpClient с помощью SSLContext.
public static String postWithSSL(String url, String jsonBody) throws Exception {
    SSLContext sslContext = getSslContext();
    SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
            sslContext, new String[]{"TLSv1.2", "TLSv1.1", "TLSv1"}, null,
            SSLConnectionSocketFactory.getDefaultHostnameVerifier());
    RequestConfig config = RequestConfig.custom()
            .setConnectTimeout(3000)
            .setSocketTimeout(3000)
            .build();
    CloseableHttpClient client = HttpClients.custom()
            .setSSLSocketFactory(sslConnectionSocketFactory)
            .setDefaultRequestConfig(config).build();
    HttpPost httpPost = new HttpPost(url);
    //httpPost.setHeaders(headers);
    httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
    httpPost.setHeader("Accept", "application/json");
    httpPost.setEntity(new StringEntity(jsonBody, StandardCharsets.UTF_8));
    HttpResponse response = client.execute(httpPost);
    HttpEntity responseEntity = response.getEntity();
    String result = EntityUtils.toString(responseEntity, "UTF-8");
    return result;
}
//双向加密 SSLContext
private static SSLContext getSslContext() throws Exception {
    //自身私钥
    KeyStore identityKeyStore = KeyStore.getInstance("jks");
    FileInputStream identityKeyStoreFile = new FileInputStream("/root/myServer.jks");
    identityKeyStore.load(identityKeyStoreFile, "password1".toCharArray());
    //服务端信任证书
    KeyStore trustKeyStore = KeyStore.getInstance("jks");
    FileInputStream trustKeyStoreFile = new FileInputStream("/root/trustKeyStore.jks");
    trustKeyStore.load(trustKeyStoreFile, "password".toCharArray());
    //构建SSLContexts
    return SSLContexts.custom()
            .loadKeyMaterial(identityKeyStore, "password1".toCharArray()) // load identity keystore
            .loadTrustMaterial(trustKeyStore, null) // load trust keystore
            .build();
}
//双向加密 SSLContext 方式二
private static SSLContext getSslContext2() throws Exception{
    //自身私钥
    KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    KeyStore keystore = KeyStore.getInstance("jks");
    keystore.load(new FileInputStream(new File("/root/myServer.jks")), "password".toCharArray());
    keyFactory.init(keystore, "password".toCharArray());
    KeyManager[] keyManagers = keyFactory.getKeyManagers();
    //服务端信任证书
    TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("SunX509");
    KeyStore tsStore = KeyStore.getInstance("jks");
    tsStore.load(new FileInputStream(new File("/root/trustKeyStore.jks")), "password".toCharArray());
    trustFactory.init(tsStore);
    TrustManager[] trustManagers = trustFactory.getTrustManagers();
    //初始化SSLContext
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(keyManagers, trustManagers, null);
    return sslContext;
}

Добро пожаловать на ошибку в тексте

Справочная статья