Java RSA без заполнения

Я пытаюсь реализовать шифрование RSA без заполнения. Мне он нужен, чтобы получить один и тот же зашифрованный текст, если я зашифрую одно и то же несколько раз. Проблема в том, что, хотя мне, кажется, это удалось, зашифрованный текст не расшифровывается. Приведенный ниже код будет работать, если я заменю «RSA / ECB / NoPadding» на «RSA».

import javax.crypto.Cipher;
import java.io.InputStream;
import java.security.*;
import java.util.Base64;

import static java.nio.charset.StandardCharsets.UTF_8;

public class RsaExample {
//https://gist.github.com/nielsutrecht/855f3bef0cf559d8d23e94e2aecd4ede
public static KeyPair generateKeyPair() throws Exception {
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
    generator.initialize(2048, new SecureRandom());
    KeyPair pair = generator.generateKeyPair();

    return pair;
}

public static KeyPair getKeyPairFromKeyStore() throws Exception {
    //Generated with:
    //  keytool -genkeypair -alias mykey -storepass s3cr3t -keypass s3cr3t -keyalg RSA -keystore keystore.jks

    InputStream ins = RsaExample.class.getResourceAsStream("/keystore.jks");

    KeyStore keyStore = KeyStore.getInstance("JCEKS");
    keyStore.load(ins, "s3cr3t".toCharArray());   //Keystore password
    KeyStore.PasswordProtection keyPassword =       //Key password
            new KeyStore.PasswordProtection("s3cr3t".toCharArray());

    KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry("mykey", keyPassword);

    java.security.cert.Certificate cert = keyStore.getCertificate("mykey");
    PublicKey publicKey = cert.getPublicKey();
    PrivateKey privateKey = privateKeyEntry.getPrivateKey();

    return new KeyPair(publicKey, privateKey);
}

public static String encrypt(String plainText, PublicKey publicKey) throws Exception {
    Cipher encryptCipher = Cipher.getInstance("RSA/ECB/NoPadding");
    encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);

    byte[] cipherText = encryptCipher.doFinal(plainText.getBytes(UTF_8));

    return Base64.getEncoder().encodeToString(cipherText);
}

public static String decrypt(String cipherText, PrivateKey privateKey) throws Exception {
    byte[] bytes = Base64.getDecoder().decode(cipherText);

    Cipher decriptCipher = Cipher.getInstance("RSA/ECB/NoPadding");
    decriptCipher.init(Cipher.DECRYPT_MODE, privateKey);

    return new String(decriptCipher.doFinal(bytes), UTF_8);
}

public static String sign(String plainText, PrivateKey privateKey) throws Exception {
    Signature privateSignature = Signature.getInstance("SHA256withRSA");
    privateSignature.initSign(privateKey);
    privateSignature.update(plainText.getBytes(UTF_8));

    byte[] signature = privateSignature.sign();

    return Base64.getEncoder().encodeToString(signature);
}

public static boolean verify(String plainText, String signature, PublicKey publicKey) throws Exception {
    Signature publicSignature = Signature.getInstance("SHA256withRSA");
    publicSignature.initVerify(publicKey);
    publicSignature.update(plainText.getBytes(UTF_8));

    byte[] signatureBytes = Base64.getDecoder().decode(signature);

    return publicSignature.verify(signatureBytes);
}

public static void main(String... argv) throws Exception {
    //First generate a public/private key pair
    KeyPair pair = generateKeyPair();
    //KeyPair pair = getKeyPairFromKeyStore();

    //Our secret message
    String message = "the answer to life the universe and everything";

    //Encrypt the message
    String cipherText = encrypt(message, pair.getPublic());
    System.out.println("Cipher 1 = "+ cipherText);

    String cipherText2 = encrypt(message, pair.getPublic());
    System.out.println("Cipher 2 = "+ cipherText2);

    //Now decrypt it
    String decipheredMessage = decrypt(cipherText, pair.getPrivate());
    //System.out.println("Private "+pair.getPrivate().toString());
    System.out.println("Deciphered "+ decipheredMessage);

    //Let's sign our message
    String signature = sign("foobar", pair.getPrivate()); 
    System.out.println("Signature "+signature);
    //Let's check the signature
    boolean isCorrect = verify("foobar", signature, pair.getPublic());
    System.out.println("Signature correct: " + isCorrect);
}
}

Любая помощь будет оценена.

Как указано в спецификациях (docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html) ‌, реализация платформы Java требуется для поддержки списка преобразований шифров, в которых нет RSA / ECB / NoPadding. Это может объяснить, почему это не работает. В любом случае должно быть сообщение об ошибке, но его нет. Это странно.

Alexandre Fenyo 10.12.2018 19:54

Любая идея о том, как я могу установить собственное заполнение (а не рандомизировать)?

antonio nehme 12.12.2018 12:35

Вы можете использовать BouncyCastle, он поддерживает "RSA / NONE / NoPadding". Обратите внимание, что размер сообщения должен быть ограничен некоторым небольшим значением, поскольку нет механизма для цепочки блоков.

Alexandre Fenyo 12.12.2018 12:53
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
2 604
0

Другие вопросы по теме