Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > алгоритм RSA не всегда работает


Автор: 4epT 2.11.2010, 16:37
Добрый день! Скачал в интернете класс который позволяет шифровать и расшифровывать методом RSA. Вот исходный код:

Код

import java.math.BigInteger;
import java.security.SecureRandom;


public class RSA {
   private final static BigInteger one      = new BigInteger("1");
   private final static SecureRandom random = new SecureRandom();

   private BigInteger privateKey;
   private BigInteger publicKey;
   private BigInteger modulus;

   // generate an N-bit (roughly) public and private key
   RSA(int N) {
      BigInteger p = BigInteger.probablePrime(N/2, random);
      BigInteger q = BigInteger.probablePrime(N/2, random);
      BigInteger phi = (p.subtract(one)).multiply(q.subtract(one));

      modulus    = p.multiply(q);
      publicKey  = new BigInteger("65537");     // common value in practice = 2^16 + 1
      privateKey = publicKey.modInverse(phi);
   }


   BigInteger encrypt(BigInteger message) {
      return message.modPow(privateKey, modulus);
   }

   BigInteger decrypt(BigInteger encrypted) {
      return encrypted.modPow(publicKey, modulus);
   }

    @Override
   public String toString() {
      String s = "";
      s += "public  = " + publicKey  + "\n";
      s += "private = " + privateKey + "\n";
      s += "modulus = " + modulus;
      return s;
   }
}


дело в том что если шифровать простой текст, то все хорошо работает к примеру вот такой аод работает:

Код

RSA key = new RSA(2048);

        // create message by converting string to integer
        String s = "Hello";
        
        byte[] bytes = s.getBytes();
        BigInteger message = new BigInteger(bytes);

        BigInteger encrypt = key.encrypt(message);
        BigInteger decrypt = key.decrypt(encrypt);
        System.out.println("message   = " + message);
        System.out.println("encrpyted = " + encrypt);
        System.out.println("decrypted = " + decrypt);


но если шифровтаь хеш этого текста то получаеться черт знате что. Вот код который не работает:

Код

RSA key = new RSA(2048);

        // create message by converting string to integer
        String s = "Hello";

        MessageDigest md = MessageDigest.getInstance("MD5");

        byte[] bytes = s.getBytes();

        md.update(bytes);
        byte[] bytesHash = md.digest();
        
        BigInteger message = new BigInteger(bytesHash);

        BigInteger encrypt = key.encrypt(message);
        BigInteger decrypt = key.decrypt(encrypt);
        System.out.println("message   = " + message);
        System.out.println("encrpyted = " + encrypt);
        System.out.println("decrypted = " + decrypt);


в чем может быть проблема? Или подскажите где можно взять реализацию RSA на Java ... RSA нужен именно для ЭЦП (Электронно цифровой подписи)

Автор: Skipy 2.11.2010, 18:57
Цитата(4epT @ 2.11.2010,  16:37)
Или подскажите где можно взять реализацию RSA на Java ... 

RSA на Java можно взять в самой Java.  http://download.oracle.com/javase/6/docs/technotes/guides/security/index.html

Неожиданно, правда?

Автор: 4epT 2.11.2010, 19:39
Цитата(Skipy @ 2.11.2010,  18:57)
Цитата(4epT @ 2.11.2010,  16:37)
Или подскажите где можно взять реализацию RSA на Java ... 

RSA на Java можно взять в самой Java.  http://download.oracle.com/javase/6/docs/technotes/guides/security/index.html

Неожиданно, правда?

смешно конечно но скачать исходник у меня не получается

Автор: jk1 2.11.2010, 20:44
Цитата

смешно конечно но скачать исходник у меня не получается 


Ничего не надо скачивать, этот исходник в составе JDK есть.

1.Генерируете ключ:

Код

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.genKeyPair();
Key publicKey = kp.getPublic();
Key privateKey = kp.getPrivate();


2. Шифруете

Код

public byte[] rsaEncrypt(byte[] data) {
  Cipher cipher = Cipher.getInstance("RSA");
  cipher.init(Cipher.ENCRYPT_MODE, pubKey);
  byte[] cipherData = cipher.doFinal(src);
  return cipherData;
}

Автор: 4epT 2.11.2010, 23:30
jk1, спасибо большое за помощь) помогло!
Но теперь столкнулся с другой проблемой ... мне нужно этот зашиврованый текст дописать в конец сообщения а потом извлечь его расшифровать. НА тапе конвертирования из массива байтов в строку и из строки обратно в массив байтов изменяются значения =(( как это правильно сделать? я делаю вот так:

Код

          byte[] sign = encrypt(hash);
          String signStr = new String(sign);


и обратно:

Код

         byte[] sign = signStr.getBytes();

Автор: jk1 3.11.2010, 09:59
Цитата

String signStr = new String(sign);


Вот так никогда поступать не стоит. Стока как контейнер массива байтов не работает, потому что воспринимает байты с учетом кодировки.
В вашем случае байты надо переводить в стоковый вид посредством Base64 кодирования:

Код

String digest = (new BASE64Encoder()).encode(bytes); 


Тут правда следует оговориться, что эта реализация B64 будет доступна только на JDK от Oracle, поэтому правильнее будет включить в состав исходников реализацию B64, например http://migbase64.sourceforge.net/

Автор: dorogoyIV 3.11.2010, 11:12
sorry
its offtopic  smile 

jk1, молодец, помнится только ссылками кормил, а теперь коды пишешь  smile 
приятно даже смотреть на это  smile 
плюс тебе

Автор: jk1 3.11.2010, 11:31
Offtopic:
Цитата

молодец, помнится только ссылками кормил, а теперь коды пишешь

Времени свободного стало побольше, хватает и на примеры.
Цитата

плюс тебе 

Спасибо

Автор: 4epT 3.11.2010, 17:38
jk1, спасибо за класс Base64. Он помог решить эту проблему))) но все равно что то у меня не получаеться =(

при декодировании в пределах одной функции все хорошо. Хешь (MD5) сообщения совпадает с расшифрованным. Вот кусочек кода:

Код

            byte[] hash = md.digest();

            byte[] sign = encrypt(hash);

            String signStr = Base64.encodeToString(sign, false);
            message.setLengthSign(signStr.length());
            message.addSignToMessage(signStr);

            byte[] decrypt;
            decrypt = decrypt(Base64.decode(message.getSign()));


и делаю точно такой же вызов декодирования, но уже из другой функции:

Код

            byte[] decrypt;
            decrypt = decrypt(Base64.decode(message.getSign()));


и массивы байт отличаються ...

методы вызываю вот так вот:

Код

        Message message = new Message("Hello, world!");

        ECP.signMessage(message);

        System.out.println(ECP.verify(message));



кто нибудь может подсказать, где я ошибся?))

Автор: jk1 3.11.2010, 23:11
Цитата

кто нибудь может подсказать, где я ошибся?))


А вы случайно ключи не перегенерируете для каждого вызова?

Автор: 4epT 3.11.2010, 23:29
Цитата(jk1 @ 3.11.2010,  23:11)
Цитата

кто нибудь может подсказать, где я ошибся?))


А вы случайно ключи не перегенерируете для каждого вызова?

Ключи статические ... инициализируються в статической области:

Код

{
              //Генерация ключей ...
}


но для уверенности сейчас выведу ключи в обеих методах.

Автор: 4epT 4.11.2010, 00:09
ключи одинаковые =(
есть еще варианты?)

Автор: jk1 4.11.2010, 09:24
Цитата

есть еще варианты?) 

На основании приведенного нет. Вы не могли бы запостить несколько классов целиком, чтобы я мог воспроизвести проблему? Особенно интересуют классы ECP и Message.

Автор: 4epT 4.11.2010, 10:19
Цитата(jk1 @ 4.11.2010,  09:24)
Цитата

есть еще варианты?) 

На основании приведенного нет. Вы не могли бы запостить несколько классов целиком, чтобы я мог воспроизвести проблему? Особенно интересуют классы ECP и Message.

да, без проблем.

ECP
Код

package testrsa;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class ECP
{
    private static Key publicKey = null;
    private static Key privateKey = null;
    private static final int sizeKeys = 1024;

    public ECP()
    {
        

    }

    static
    {
        KeyPairGenerator kpg;
        try
        {
            kpg = KeyPairGenerator.getInstance("RSA");
            kpg.initialize(sizeKeys);
            KeyPair kp = kpg.genKeyPair();
            publicKey = kp.getPublic();
            privateKey = kp.getPrivate();
        }
        catch (NoSuchAlgorithmException ex)
        {
            System.out.println(ex.getMessage());
        }
    }

    public static Message signMessage(Message message)
    {
        try
        {
            if(publicKey == null || privateKey == null)
                return null;

            MessageDigest md = MessageDigest.getInstance("MD5");

            md.update(message.getDataBytes());
            byte[] hash = md.digest();

            System.out.println("encode");
            System.out.println(publicKey.toString());
            System.out.println(privateKey.toString());
            byte[] sign = encrypt(hash);

            String signStr = Base64.encodeToString(sign, false);
            message.setLengthSign(signStr.length());
            message.addSignToMessage(signStr);

            byte[] decrypt;
            decrypt = decrypt(Base64.decode(message.getSign()));

            System.out.println(Arrays.toString(decrypt));

            //message.addSignTest(sign);

            return message;
        }
        catch (NoSuchAlgorithmException ex)
        {
            System.out.println(ex.getMessage());
            return null;
        }
    }

    public static boolean verify(Message message)
    {
        try 
        {
            if(publicKey == null || privateKey == null)
                return false;
            if(!message.isIsSign())
                return false;
            
            MessageDigest md = MessageDigest.getInstance("MD5");

            String data = message.getMessage();

            System.out.println("decode");
            System.out.println(publicKey.toString());
            System.out.println(privateKey.toString());
            byte[] decrypt;
            decrypt = decrypt(Base64.decode(message.getSign()));

            md.update(data.getBytes());

            byte[] hash = md.digest();

            System.out.println("Verify:");
            System.out.println(Arrays.toString(decrypt));
            System.out.println(Arrays.toString(hash));

            return Arrays.equals(decrypt, hash);
        }
        catch (NoSuchAlgorithmException ex)
        {
            System.out.println(ex.getMessage());
            return false;
        }
    }

    private static byte[] encrypt(byte[] data)
    {
        Cipher cipher;
        byte[] cipherData = null;
        try
        {
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            cipherData = cipher.doFinal(data);
        }
        catch (NoSuchAlgorithmException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (NoSuchPaddingException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (InvalidKeyException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (IllegalBlockSizeException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (BadPaddingException ex)
        {
            System.err.println(ex.getMessage());
        }
        finally
        {
            return cipherData;
        }

    }


    private static byte[] decrypt(byte[] data)
    {
        Cipher cipher;
        byte[] cipherData = null;
        try
        {
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            cipherData = cipher.doFinal(data);
        }
        catch (NoSuchAlgorithmException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (NoSuchPaddingException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (InvalidKeyException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (IllegalBlockSizeException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (BadPaddingException ex)
        {
            System.err.println(ex.getMessage());
        }
        finally
        {
            return cipherData;
        }

    }
    
}



Message
Код

package testrsa;

public class Message
{
    private String message;
    private boolean isSign = false;
    private int lengthSign = 0;
    private byte[] signTest;

    public Message(String message) 
    {
        this.message = message;
    }

    public boolean isIsSign() 
    {
        return isSign;
    }

    public void setIsSign(boolean isSign) 
    {
        this.isSign = isSign;
    }

    public int getLengthSign() 
    {
        return lengthSign;
    }

    public void setLengthSign(int lengthSign) 
    {
        this.lengthSign = lengthSign;
    }

    public String getMessage() 
    {
        return message;
    }

    public void setMessage(String message) 
    {
        this.message = message;
    }

    public byte[] getDataBytes()
    {
        return this.message.getBytes();
    }

    public void addSignToMessage(String sign)
    {
        this.message += sign;
        this.setIsSign(true);
    }

    public String getSign()
    {
        if(this.isSign)
        {
            return this.message.substring(this.message.length() - this.lengthSign);
        }
        else
        {
            return null;
        }
    }

    public String getData()
    {
        if(this.isSign)
        {
            return this.message.substring(0 , this.message.length() - this.lengthSign);
        }
        else
        {
            return null;
        }
    }

    public void addSignTest(byte[] sign)
    {
        this.signTest = sign;
        this.setIsSign(true);
    }

    public byte[] getSignTest()
    {
        return this.signTest;
    }

}


Автор: jk1 4.11.2010, 11:02
Проблема в запутанной логике класса Message. Предлагаю такой вариант:
Код

public class Message {
    private String message;
    private String signature;

    public Message(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getSignature() {
        return signature;
    }

    public void setSignature(String signature) {
        this.signature = signature;
    }
}

Код


import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
public class ECP
{
    private static Key publicKey = null;
    private static Key privateKey = null;
    private static final int sizeKeys = 1024;
    public ECP()
    {

    }
    static
    {
        KeyPairGenerator kpg;
        try
        {
            kpg = KeyPairGenerator.getInstance("RSA");
            kpg.initialize(sizeKeys);
            KeyPair kp = kpg.genKeyPair();
            publicKey = kp.getPublic();
            privateKey = kp.getPrivate();
        }
        catch (NoSuchAlgorithmException ex)
        {
            System.out.println(ex.getMessage());
        }
    }
    public static Message signMessage(Message message)
    {
        try
        {
            if(publicKey == null || privateKey == null)
                return null;
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(message.getMessage().getBytes());
            byte[] hash = md.digest();
            System.out.println("encode");
            System.out.println(publicKey.toString());
            System.out.println(privateKey.toString());
            byte[] sign = encrypt(hash);
            String signStr = Base64.encodeToString(sign, false);

            message.setSignature(signStr);
            byte[] decrypt;
            decrypt = decrypt(Base64.decode(message.getSignature()));
            System.out.println(Arrays.toString(decrypt));
            //message.addSignTest(sign);
            return message;
        }
        catch (NoSuchAlgorithmException ex)
        {
            System.out.println(ex.getMessage());
            return null;
        }
    }
    public static boolean verify(Message message)
    {
        try
        {
            if(publicKey == null || privateKey == null)
                return false;
            if(message.getSignature() == null)
                return false;

            MessageDigest md = MessageDigest.getInstance("MD5");
            String data = message.getMessage();
            System.out.println("decode");
            System.out.println(publicKey.toString());
            System.out.println(privateKey.toString());
            byte[] decrypt;
            decrypt = decrypt(Base64.decode(message.getSignature()));
            md.update(data.getBytes());
            byte[] hash = md.digest();
            System.out.println("Verify:");
            System.out.println(Arrays.toString(decrypt));
            System.out.println(Arrays.toString(hash));
            return Arrays.equals(decrypt, hash);
        }
        catch (NoSuchAlgorithmException ex)
        {
            System.out.println(ex.getMessage());
            return false;
        }
    }
    private static byte[] encrypt(byte[] data)
    {
        Cipher cipher;
        byte[] cipherData = null;
        try
        {
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            cipherData = cipher.doFinal(data);
        }
        catch (NoSuchAlgorithmException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (NoSuchPaddingException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (InvalidKeyException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (IllegalBlockSizeException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (BadPaddingException ex)
        {
            System.err.println(ex.getMessage());
        }
        finally
        {
            return cipherData;
        }
    }
    private static byte[] decrypt(byte[] data)
    {
        Cipher cipher;
        byte[] cipherData = null;
        try
        {
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            cipherData = cipher.doFinal(data);
        }
        catch (NoSuchAlgorithmException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (NoSuchPaddingException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (InvalidKeyException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (IllegalBlockSizeException ex)
        {
            System.err.println(ex.getMessage());
        }
        catch (BadPaddingException ex)
        {
            System.err.println(ex.getMessage());
        }
        finally
        {
            return cipherData;
        }
    }

}

Автор: 4epT 4.11.2010, 13:50
jk1, спасибо за помощь) проблема была действительно из за запутанной логики класса Message, а именно в неправильном именовании методов, из за этого и запутался .. все работает.
Спасибо!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)