Как спроектировать безопасный внешний интерфейс? Проверьте подпись

интервью Java

предисловие

На собеседованиях нас часто спрашивают, как спроектировать безопасный внешний интерфейс?На самом деле мы можем ответить на это, подписав и проверив, что сделает ваш интерфейс более безопасным. Далее эта статья поможет вам узнать о подписании и проверке. От теории к реальному бою, давай~

  • Понятия, связанные с криптографией
  • Концепция проверки подписи
  • Зачем нужно подписывать и подтверждать
  • Введение в алгоритмы шифрования
  • API для проверки подписи
  • Реализация кода проверки подписи
  • Общественный номер: маленький мальчик собирает улиток

Эта статья попала в личный гитхаб, если статья окажется полезной, вы можете поставить ей звезду:

GitHub.com/Я бы хотел 123/Java…

Понятия, связанные с криптографией

открытый текст, зашифрованный текст, ключ, шифрование, дешифрование

  • Открытый текст: Относится к информации/данным, которые не зашифрованы.
  • Зашифрованный текст: после того, как открытый текст будет зашифрован алгоритмом шифрования, он станет зашифрованным текстом для обеспечения безопасности данных.
  • Ключ: параметр, который вводится в алгоритм, преобразующий открытый текст в зашифрованный текст или преобразующий зашифрованный текст в открытый текст. Ключи делятся на симметричные и асимметричные.
  • Шифрование: процесс преобразования открытого текста в зашифрованный.
  • Расшифровка: процесс восстановления зашифрованного текста в открытый текст.

Симметричное шифрование, асимметричное шифрование

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

  • Асимметричное шифрование. Для алгоритмов асимметричного шифрования требуются два ключа (открытый ключ и закрытый ключ). Открытый ключ и закрытый ключ существуют парами, и если данные зашифрованы открытым ключом, только соответствующий закрытый ключ может их расшифровать.

Что такое открытый ключ и закрытый ключ?

  • Открытый ключ и закрытый ключ — это ключи, которые существуют парами.Если данные зашифрованы с помощью открытого ключа, их можно расшифровать только с помощью соответствующего закрытого ключа.
  • На самом деле открытый ключ — это открытый ключ, а закрытый ключ — это секретный ключ, который вы хотите сохранить в тайне.
  • Алгоритм асимметричного шифрования требует пары открытого и закрытого ключей~

Предположим, у вас есть файл, который вы шифруете с помощью буквы а, а расшифровывать может только буква b; или вы шифруете с помощью b, а расшифровывать может только буква а, тогда а и b являются парой открытого и закрытого ключей. Если ключ a является открытым, а ключ b хранится в частном порядке, то ключ a является открытым ключом, а ключ b — закрытым ключом. Наоборот, если b делается общедоступным, необходимо сохранить a. В это время секретный ключ b является открытым ключом, а секретный ключ a — закрытым ключом.

Концепция проверки подписи

  • "добавить подпись": Используйте хеш-функцию, чтобы создать дайджест сообщения из исходного сообщения, а затем зашифровать дайджест с помощью закрытого ключа, чтобы получить цифровую подпись, соответствующую сообщению."Обратите внимание, что процесс подписания должен включать в себя некоторые специальные личные вещи, такие как личные закрытые ключи."Как правило, запрашивающий"Цифровая подпись и исходное сообщение"вместе с получателем.

  • "проверка подписи": После того, как получатель получит исходное сообщение и цифровую подпись, используйте"та самая хэш-функция"Сгенерируйте дайджест A из сообщения. Кроме того, расшифруйте цифровую подпись с помощью открытого ключа, предоставленного другой стороной, и получите реферат B. Сравнив, совпадают ли A и B, вы можете узнать, было ли сообщение подделано.

Эту картинку в интернете легче понять:

Зачем нужна проверка подписи

В предыдущем разделе мы уже познакомились с концепцией подписи и проверки подписи, так зачем же нам нужна подпись подпись и проверка подписи? Некоторым друзьям может показаться, что мы не используем"Шифрование с открытым ключом, дешифрование с закрытым ключом"Хорошо?

Далее возьмем демо.

Предположим, что сейчас есть компания А, и она хочет получить доступ к системе переводов компании С. Сначала компания C отправляла свой открытый ключ компании A, а закрытый ключ хранила у себя. Когда продавец на стороне компании A инициирует перевод, компания A сначала использует открытый ключ компании C для шифрования сообщения запроса. Когда зашифрованное сообщение достигает системы перевода компании C, компания C использует свой собственный закрытый ключ для расшифровки сообщения. Предположим, что зашифрованное сообщение получено посредником Актером в процессе передачи, и он также подавлен, потому что у него нет закрытого ключа и он не может есть лебединое мясо. Я изначально хотел изменить сообщение и перевести 100 миллионов на свой счет, ха-ха. Эта реализация кажется бесшовной и стабильной.

Однако, если компания C отправила открытый ключ компании A в начале, он был получен посредником Актером, тогда у Jiangzi возникли бы проблемы.

Актер, посредник, перехватил открытый ключ C и отправил свой открытый ключ компании A. A ошибочно подумал, что это открытый ключ компании C. Когда А инициирует передачу, он использует открытый ключ Актера для шифрования сообщения-запроса, а актор перехватывает зашифрованное сообщение во время передачи, в это время он расшифровывает его своим закрытым ключом, а затем модифицирует сообщение (сам себе Передача 100 миллионов), зашифровать его с помощью открытого ключа C и отправить компании C. После того, как компания C получит сообщение, она продолжит его расшифровку с помощью собственного закрытого ключа. В итоге трансферный счет компании А потерял 100 миллионов?

Как компания C различает, исходит ли сообщение от A или оно было изменено посредником? Чтобы продемонстрировать подлинность личности и сообщения, требуется"проверка подписи"Ла!

Компания A также отправляет свой открытый ключ компании C, а закрытый ключ хранится у нее. При инициировании передачи сначала подпишите сообщение запроса своим закрытым ключом, а затем получите собственную цифровую подпись. Затем отправьте цифровую подпись вместе с сообщением запроса в компанию C. После того, как компания C получает сообщение, она использует открытый ключ A для проверки подписи. Если содержимое исходного сообщения и дайджест цифровой подписи несовместимы, это означает, что сообщение было подделано~

У некоторых друзей могут возникнуть сомнения: предположим, что когда А отправляет свой открытый ключ компании С, он также перехватывается посредником Актером. Что ж, давайте смоделируем волну Актера и перехватим публичный ключ, чтобы посмотреть, что Актер может сделать~ Ха-ха

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

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

Введение в общие алгоритмы, связанные с шифрованием

  • алгоритм дайджеста сообщения
  • Алгоритм симметричного шифрования
  • Алгоритм асимметричного шифрования
  • Национальный секретный алгоритм

Алгоритм дайджеста сообщения:

  • Одни и те же данные открытого текста получат одно и то же значение результата зашифрованного текста с помощью одного и того же алгоритма дайджеста сообщения.
  • Данные обрабатываются алгоритмом дайджеста сообщения, и полученное значение результата дайджеста не может быть восстановлено до данных до обработки.
  • Алгоритмы дайджеста данных также известны как алгоритмы хеширования или алгоритмы хеширования.
  • Алгоритм дайджеста сообщения обычно используется для проверки подписи.

Алгоритмы дайджеста сообщения в основном делятся на три категории: MD (дайджест сообщения, алгоритм дайджеста сообщения), SHA (алгоритм безопасного хеширования, алгоритм безопасного хеширования) и MAC (код аутентификации сообщения, алгоритм кода аутентификации сообщения).

Семейство алгоритмов MD

Семейство MD (Message Digest, алгоритм дайджеста сообщения), включая MD2, MD4, MD5.

  • Результатом вычисления MD2, MD4 и MD5 является 128-битное (т.е. 16-байтовое) хеш-значение, которое используется для обеспечения полной и согласованной передачи информации.
  • Алгоритм MD2 медленнее, но относительно безопасен, MD4 быстр, но менее безопасен, а MD5 более безопасен и быстрее, чем MD4.
  • MD5 широко используется для проверки целостности данных, дайджеста данных (сообщений), шифрования данных и т. д.
  • MD5 может быть взломан.Для данных, требующих высокой безопасности, эксперты обычно рекомендуют использовать другие алгоритмы, такие как SHA-2.В 2004 году было подтверждено, что алгоритм MD5 не может предотвратить атаки столкновений, поэтому он не подходит для сертификации безопасности, например как общедоступное шифрование SSL, аутентификация по ключу или цифровая подпись.

В качестве примера посмотрите, как получить значение MD5 строки:

public class MD5Test {

    public static void main(String[] args) throws UnsupportedEncodingException {
        String s = "123";
        byte[] result = getMD5Bytes(s.getBytes());
        StringBuilder stringBuilder = new StringBuilder();
        for (byte temp : result) {
            if (temp >= 0 && temp < 16) {
                stringBuilder.append("0");
            }
            stringBuilder.append(Integer.toHexString(temp & 0xff));
        }
        System.out.println(s + ",MD5加密后:" + stringBuilder.toString());
    }

    private static byte[] getMD5Bytes(byte[] content) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            return md5.digest(content);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
}


результат операции:

123,MD5加密后:202cb962ac59075b964b07152d234b70

Семейство алгоритмов ShA

SHA (Secure Hash Algorithm, Безопасный алгоритм хэширования), включая SHA-0, SHA-1, SHA-2 (SHA-256, SHA-512, SHA-224, SHA-384 и т. д.), SHA-3. Он реализован на основе алгоритма МД, а отличие от алгоритма МД в том, что"Абстрактная длина", дайджест алгоритма SHA"Большая длина для большей безопасности".

  • SHA-0, предшественник SHA-1, был отозван АНБ вскоре после его выпуска, поскольку он содержал ошибки, снижающие криптографическую безопасность.
  • SHA-1 широко используется во многих протоколах безопасности, включая TLS, GnuPG, SSH, S/MIME и IPsec, и является преемником MD5.
  • SHA-2 включает SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256. Его алгоритм в основном похож на SHA-1, и явных слабых мест пока нет.
  • SHA-3 был официально выпущен в 2015 году из-за"Появляется успешное нарушение MD5", а также метод теоретического взлома SHA-0 и SHA-1, появился SHA-3. Он отличается от предыдущего алгоритма тем, что является альтернативным алгоритмом криптографического хеширования.

Чаще используются такие алгоритмы, как SHA-1, SHA-2 (SHA-256, SHA-512, SHA-224, SHA-384), давайте взглянем на сравнение с MD5.

Тип алгоритма длина дайджеста (биты) Максимальная длина входного сообщения (биты) атака столкновением (биты) Пример производительности (МиБ/с)
MD5 128 неограниченный ≤18 (обнаружено столкновение) 335
SHA-1 160 2 ^ 64 - 1 192
SHA-224 224 2 ^ 64 - 1 112 139
SHA-256 256 2 ^ 64 - 1 128 139
SHA-384 384 2 ^ 128 - 1 192 154
SHA-512 512 2 ^ 128 - 1 256 154

Семейство алгоритмов MAC

Алгоритм MAC MAC (Message Authentication Code, алгоритм кода аутентификации сообщения) представляет собой хеш-функцию с ключом. Введите ключ и сообщение, выведите дайджест сообщения. Он объединяет две серии алгоритмов дайджеста сообщений, MD и SHA.

  • Алгоритмы серии MD: HmacMD2, HmacMD4 и HmacMD5;
  • Семейство алгоритмов SHA: HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384 и HmacSHA512.

Алгоритм симметричного шифрования

Использование шифрования и дешифрования"тот же ключ"Алгоритм шифрования является симметричным алгоритмом шифрования. Общие алгоритмы симметричного шифрования включают AES, 3DES, DES, RC5, RC6 и т. д.

DES

Стандарт шифрования данных (англ. Data Encryption Standard, сокращенно DES) — алгоритм блочного шифрования с симметричным ключом. Алгоритм DES имеет три входных параметра: ключ, данные и режим.

  • Ключ: 7 байтов с общим количеством бит 56, который является рабочим ключом алгоритма DES;
  • Данные: 8 байт 64 бита, это данные, которые нужно зашифровать или расшифровать;
  • Режим: зашифровать или расшифровать.

3DES

Алгоритм тройного шифрования данных (англ. Triple Data Encryption Algorithm, также известный как 3DES (Triple DES) — это блочный шифр шифрования с симметричным ключом, который эквивалентен трем применениям алгоритма стандарта шифрования данных (DES) к каждому блоку данных.

AES

AES, расширенный стандарт шифрования (англ. Advanced Encryption Standard), также известный как шифрование Rijndael в криптографии, представляет собой стандарт блочного шифрования, принятый федеральным правительством США.

  • Принята симметричная блочная система шифрования, длина ключа составляет 128 бит, 192 бит, 256 бит, а длина блока составляет 128 бит.
  • По сравнению с DES, AES обладает большей безопасностью, эффективностью и гибкостью.

Алгоритм асимметричного шифрования

Алгоритмы асимметричного шифрования требуют два ключа: открытый ключ и закрытый ключ. Открытый ключ и закрытый ключ существуют парами. Если данные зашифрованы открытым ключом, их можно расшифровать только с помощью соответствующего закрытого ключа. Основные алгоритмы асимметричного шифрования: RSA, Elgamal, DSA, D-H, ECC.

Алгоритм RSA

  • Алгоритм шифрования RSA — это асимметричный алгоритм шифрования, широко используемый в шифровании и цифровой подписи.
  • Принцип алгоритма RSA: произведение двух больших простых чисел чрезвычайно сложно разложить на множители, поэтому произведение можно сделать общедоступным в качестве ключа шифрования.
  • RSA является наиболее широко изученным алгоритмом с открытым ключом. Он был протестирован различными атаками с момента его предложения до настоящего времени. В настоящее время он считается одной из лучших схем с открытым ключом.

DSA

  • DSA (Digital Signature Algorithm, алгоритм цифровой подписи) также является алгоритмом асимметричного шифрования.
  • Разница между DSA и RSA заключается в том, что DSA используется только для цифровых подписей и не может использоваться для шифрования и дешифрования данных. Его безопасность сравнима с RSA, но его производительность выше, чем у RSA.

ECC-алгоритм

  • ECC (криптография на эллиптических кривых), основанная на шифровании на эллиптических кривых.
  • Основное преимущество Ecc заключается в том, что в некоторых случаях он использует ключи меньшего размера, чем другие методы, такие как алгоритм шифрования RSA, обеспечивая сравнимый или более высокий уровень безопасности.
  • Одним из его недостатков является то, что операции шифрования и дешифрования требуют больше времени для реализации, чем другие механизмы (алгоритм интенсивно использует ЦП по сравнению с алгоритмом RSA).

Национальный секретный алгоритм

Государственной тайной является отечественный алгоритм шифрования, признанный Государственным управлением криптографии. Чтобы обеспечить безопасность коммерческой криптографии, Национальное управление по управлению коммерческой криптографией сформулировало ряд криптографических стандартов, а именно SM1, SM2, SM3, SM4 и другие национальные криптографические алгоритмы.

SM1

  • SM1 — это алгоритм симметричного шифрования со степенью шифрования 128 бит, реализованный на аппаратном уровне.
  • Сила шифрования и производительность SM1 сравнимы с AES.

SM2

  • SM2 в основном включает три части: алгоритм подписи, алгоритм обмена ключами, алгоритм шифрования.
  • SM2 используется для замены алгоритма шифрования RSA, который основан на ECC и менее эффективен.

SM3

  • SM3 — это внутренний алгоритм дайджеста сообщений.
  • Он подходит для цифровой подписи и проверки в коммерческих криптографических приложениях, генерации и проверки кодов аутентификации сообщений и генерации случайных чисел.

SM4

  • SM4 — это алгоритм группировки, используемый в продуктах для беспроводных локальных сетей.
  • Длина блока этого алгоритма составляет 128 бит, а длина ключа — 128 бит.
  • И алгоритм шифрования, и алгоритм расширения ключа используют нелинейную итеративную структуру с 32 раундами.
  • Структура алгоритма дешифрования такая же, как у алгоритма шифрования, за исключением того, что ключи раунда используются в обратном порядке, а ключ раунда дешифрования — это порядок, обратный ключу раунда шифрования.
  • Его функция аналогична DES международного алгоритма.

Java API, связанный с проверкой подписи

В этом разделе давайте сначала представим API, необходимые для проверки подписи~

API, связанный с подписью

- java.security.Signature.getInstance(String algorithm); //根据对应算法,初始化签名对象
- KeyFactory.getInstance(String algorithm);// 根据对应算法,生成KeyFactory对象
- KeyFactory.generatePrivate(KeySpec keySpec); //生成私钥
- java.security.Signature.initSign(PrivateKey privateKey) //由私钥,初始化加签对象
- java.security.Signature.update(byte[] data)  //把原始报文更新到加签对象
- java.security.Signature.sign();//加签

"Signature.getInstance(String algorithm);"

  • Инициализировать объект подписи по соответствующему алгоритму
  • Параметр алгоритма может принимать такие параметры, как SHA256WithRSA или MD5WithRSA.SHA256WithRSA означает, что алгоритм SHA256 используется для создания дайджеста, а алгоритм RSA используется для добавления подписи.

"KeyFactory.getInstance(String algorithm);"

  • Сгенерируйте объект KeyFactory по соответствующему алгоритму, например, если ваши открытый и закрытый ключи используют алгоритм RSA, то передайте в RSA

"KeyFactory.generatePrivate(KeySpec keySpec)"

  • Чтобы сгенерировать закрытый ключ, подпись является закрытым ключом, поэтому сначала необходимо создать объект закрытого ключа с помощью KeyFactory.

"Signature.initSign(PrivateKey privateKey)"

  • В подписи используется закрытый ключ, поэтому передайте закрытый ключ для инициализации объекта подписи.

"Signature.update(byte[] data)"

  • Обновите исходное сообщение до объекта подписи

"java.security.Signature.sign();"

  • выполнить операцию подписи

API, связанные с проверкой подписи

- java.security.Signature.getInstance(String algorithm); //根据对应算法,初始化签名对象
- KeyFactory.getInstance(String algorithm);// 根据对应算法,生成KeyFactory对象
- KeyFactory.generatePublic(KeySpec keySpec); //生成公钥
- java.security.Signature.initVerify(publicKey); //由公钥,初始化验签对象
- java.security.Signature.update(byte[] data)  //把原始报文更新到验签对象
- java.security.Signature.verify(byte[] signature);//验签

"Signature.getInstance(String algorithm)"

  • Инициализируйте объект подписи согласно соответствующему алгоритму.Обратите внимание, что для проверки подписи и добавления подписи необходимо использовать одни и те же параметры алгоритма~

"KeyFactory.getInstance(String algorithm);"

  • Сгенерировать объект KeyFactory по соответствующему алгоритму

"KeyFactory.generatePublic(KeySpec keySpec);"

  • Создайте открытый ключ, используйте открытый ключ для проверки подписи, сначала создайте объект открытого ключа с помощью KeyFactory.

**Signature.initVerify(publicKey); **

  • Открытый ключ используется для проверки подписи, поэтому параметр объекта открытого ключа передается для инициализации объекта проверки подписи.

"Signature.update(byte[] data)"

  • Обновите исходное сообщение до объекта подписи

"Signature.verify(byte[] signature);"

  • Выполнить проверку подписи

Реализация кода проверки подписи

После обсуждения концепций в предыдущих разделах пришло время применить код на практике.Я использую SHA-256 в качестве алгоритма дайджеста и RSA в качестве алгоритма проверки подписи следующим образом:

package pattern;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;

/**
 * 加签验签demo
 *  @Author 捡田螺的小男孩
 */
public class SignatureTest {
    //公钥字符串
    private static final String PUBLIC_KEY_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaJzVjC5K6kbS2YE2fiDs6H8pB\n" +
            "JFDGEYqqJJC9I3E0Ebr5FsofdImV5eWdBSeADwcR9ppNbpORdZmcX6SipogKx9PX\n" +
            "5aAO4GPesroVeOs91xrLEGt/arteW8iSD+ZaGDUVV3+wcEdci/eCvFlc5PUuZJou\n" +
            "M2XZaDK4Fg2IRTfDXQIDAQAB";
    //私钥字符串
    private static final String PRIVATE_KEY_STR = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANonNWMLkrqRtLZg\n" +
            "TZ+IOzofykEkUMYRiqokkL0jcTQRuvkWyh90iZXl5Z0FJ4APBxH2mk1uk5F1mZxf\n" +
            "pKKmiArH09floA7gY96yuhV46z3XGssQa39qu15byJIP5loYNRVXf7BwR1yL94K8\n" +
            "WVzk9S5kmi4zZdloMrgWDYhFN8NdAgMBAAECgYA9bz1Bn0i68b2KfqRdgOfs/nbe\n" +
            "0XNN1DLQp2t7WDfRCg01iI1zPkZgyFVZWtI85f5/uIrLs5ArLosL1oNuqqc0nNne\n" +
            "CvJK+ZxvA98Hx3ZqYTzDnleR054YhofL5awbhSciYVic204DOG1rhSsYWMqtX7J7\n" +
            "3geoWL7TYdMfYXcCAQJBAPMMKsz6ZJh98EeQ1tDG5gpAGWFQkYNrxZDelP/LjeO0\n" +
            "TP3XkQnIpcaZoCs7V/rRGRGMWwQ2BUdc/01in89ZZ5ECQQDlx2oBc1CtOAm2UAhN\n" +
            "1xWrPkZWENQ53wTrwXO4qbTGDfBKon0AehLlGCSqxQ71aufLkNO7ZlX0IHTAlnk1\n" +
            "TvENAkAGSEQ69CXxgx/Y2beTwfBkR2/gghKg0QJUUkyLqBlMz3ZGAXJwTE1sqr/n\n" +
            "HiuSAiGhwH0ByNuuEotO1sPGukrhAkAMK26a2w+nzPL+u+hkrwKPykGRZ1zGH+Cz\n" +
            "19AYNKzFXJGgclCqiMydY5T1knBDYUEbj/UW1Mmyn1FvrciHoUG1AkAEMEIuDauz\n" +
            "JabEAU08YmZw6OoDGsukRWaPfjOEiVhH88p00veM1R37nwhoDMGyEGXVeVzNPvk7\n" +
            "cELg28MSRzCK";


    public static void main(String[] args) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException, IOException, InvalidKeySpecException {
        //原始报文
        String plain = "欢迎大家关注我的公众号,捡田螺的小男孩";
        //加签
        byte[] signatureByte = sign(plain);
        System.out.println("原始报文是:" + plain);
        System.out.println("加签结果:");
        System.out.println(new BASE64Encoder().encode(signatureByte));
        //验签
        boolean verifyResult = verify(plain, signatureByte);
        System.out.println("验签结果:" + verifyResult);
    }

    /**
     * 加签方法
     * @param plain
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws UnsupportedEncodingException
     * @throws SignatureException
     */
    private static byte[] sign(String plain) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, SignatureException {
        //根据对应算法,获取签名对象实例
        Signature signature = Signature.getInstance("SHA256WithRSA");
        //获取私钥,加签用的是私钥,私钥一般是在配置文件里面读的,这里为了演示方便,根据私钥字符串生成私钥对象
        PrivateKey privateKey = getPriveteKey(PRIVATE_KEY_STR);
        //初始化签名对象
        signature.initSign(privateKey);
        //把原始报文更新到对象
        signature.update(plain.getBytes("UTF-8"));
        //加签
        return signature.sign();
    }

    /**
     * 验签方法
     * @param plain
     * @param signatureByte
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws IOException
     * @throws SignatureException
     * @throws InvalidKeySpecException
     */
    private static boolean verify(String plain, byte[] signatureByte) throws NoSuchAlgorithmException, InvalidKeyException, IOException, SignatureException, InvalidKeySpecException {
        //获取公钥
        PublicKey publicKey = getPublicKey(PUBLIC_KEY_STR);
        //根据对应算法,获取签名对象实例
        Signature signature = Signature.getInstance("SHA256WithRSA");
        //初始化签名对象
        signature.initVerify(publicKey);
        //把原始报文更新到签名对象
        signature.update(plain.getBytes("UTF-8"));
        //进行验签
        return signature.verify(signatureByte);
    }

    private static PublicKey getPublicKey(String publicKeyStr) throws InvalidKeySpecException, IOException {
        PublicKey publicKey = null;
        try {
            java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec(
                    new BASE64Decoder().decodeBuffer(publicKeyStr));
            // RSA对称加密算法
            java.security.KeyFactory keyFactory;
            keyFactory = java.security.KeyFactory.getInstance("RSA");
            // 生成公钥对象
            publicKey = keyFactory.generatePublic(bobPubKeySpec);
           } catch (NoSuchAlgorithmException e) {
             e.printStackTrace();
            }
        return publicKey;
      }

    private static PrivateKey getPriveteKey(String privateKeyStr) {
        PrivateKey privateKey = null;
        PKCS8EncodedKeySpec priPKCS8;
        try {
            priPKCS8 = new PKCS8EncodedKeySpec(new BASE64Decoder().decodeBuffer(privateKeyStr));
            KeyFactory keyf = KeyFactory.getInstance("RSA");
            privateKey = keyf.generatePrivate(priPKCS8);
        } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return privateKey;
    }
}

"результат операции:"

原始报文是:欢迎大家关注我的公众号,捡田螺的小男孩
加签结果:
Oz15/aybGe42eGHbc+iMoSYHSCc8tfRskTVjjGSTPD4HjadL0CC5JUWNUW0WxHjUb4MvxWo2oeWE
Qw0+m61d+JgBMto/TWcVDcgwL/AbObsbWdQ6E/fVRqG13clkE8MyKsjt9Z7tcbwpycYTv0rUR4co
rndAVfBdtv5KeV+OXqM=
验签结果:true

Ссылка и спасибо

Публичный аккаунт WeChat