(1) Преобразование закрытого и открытого ключа ECDSA, (2) Проверка ECDSA

После этого обсуждения это простое руководство, как подписать строку с использованием алгоритма ECDSA в java без использования каких-либо сторонних библиотек. Но вопрос в следующем:

  1. Как я могу преобразовать открытый и закрытый ключ в строку? (Потому что я хочу отправить их в базу данных).
  2. Может ли кто-нибудь помочь мне создать простой учебник о том, как проверить сообщение с помощью алгоритма ECDSA в java? на данный момент мне нужно включить подпись и открытый ключ в качестве метода проверки.

Вот мой сценарий в моем Java-коде, предположим, что есть сторона отправителя и сторона получателя:

  • Сторона отправителя
package sender;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
public class Sign {    
  public static void main(String[] args) throws Exception {
      /*
       * Generate a key pair
       */
      KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
      SecureRandom random = SecureRandom.getInstance("SHA1PRNG");

      keyGen.initialize(256, random);

      KeyPair pair = keyGen.generateKeyPair();
        
      /*
      Generate the private and the public key
      */

      PrivateKey priv = pair.getPrivate();
      /*
      *and then Convert the priv key into a String;
      *HOW can i do that ? this what i'm asking
      */
                   
      PublicKey pub = pair.getPublic();
      /*
      Convert the pub key into a String;
      HOW can i do that ? this what i'm asking
      */      
       
      /*
      -------Encrypt the pub and the priv key, i do with my own code  
      -------Store the enrypted pub & priv key into the database
      -------I'm doing this with my own code
      */
        
        
      /*
      * Create a Signature object and initialize it with the private key
      */
      Signature dsa = Signature.getInstance("SHA1withECDSA");

      dsa.initSign(priv);

      String str = "This is string to sign";
      byte[] strByte = str.getBytes("UTF-8");
      dsa.update(strByte);

      /*
      * Now that all the data to be signed has been read in, generate a
      * signature for it
      */

      byte[] realSig = dsa.sign();
      System.out.println("Signature: " + 
             new BigInteger(1, realSig).toString(16));
      /*
      and Then i'm storing this signature into my database. 
      i have done with this
      */
    }
}
  • Сторона получателя
package recipient;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
 public class Verify {   
   public static void main(String[] args) throws Exception {
   /*
   Step one, taking public key from the database.
   Step two, receive the message + signature.
   Step three, split the message and signature into an "array[0]" for message,
   and "array[1] for the signature"
        
   Verify the signature <--- Here's what im asking to anybody, 
   how can i do, i mean the sample code ? 
   */  
   }
}

Извините за мой плохой английский :D


person Rhony    schedule 29.12.2014    source источник
comment
Извини, я больше никогда так не буду. Я новичок в этом stackoverflow, спасибо за предупреждение @ArtjomB.   -  person Rhony    schedule 13.01.2015


Ответы (1)


Вы задаете много разных вопросов о работе с ECDSA. Я отвечу на ваш первый вопрос о хранении базы данных здесь. Я рекомендую вам провести дополнительное исследование механики ECDSA, если вы хотите узнать, как правильно ее использовать. Примеры, приведенные здесь, в любом случае трудно понять вне контекста.

Чтобы сохранить ключи в виде строки, необходимо сначала получить массив байтов, представляющий ключ в его закодированном формате (примечание: закодированный, а не зашифрованный). Это можно сделать с помощью метода getEncoded() из класса Key, который является суперинтерфейсом как для PublicKey, так и для PrivateKey.

Пример:

PrivateKey key = // ...

byte[] enc_key = key.getEncoded();

// Byte array to string

StringBuilder key_builder = new StringBuilder();

for(byte b : enc_key){
    key_builder.append(String.format("%02x", b));
}

String serialized_key = key_builder.toString();

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

Пример:

String serialzed_key = // ...

byte[] encoded_key = // serialzed_key -> byte array conversion

// If key is private, use PKCS #8

PKCS8EncodedKeySpec formatted_private = new PKCS8EncodedKeySpec(encoded_key);

// or, if key is public, use X.509

X509EncodedKeySpec formatted_public = new X509EncodedKeySpec(encoded_key);

// Retrieve key using KeyFactory

KeyFactory kf = KeyFactory.getInstance("EC");

PublicKey pub = kf.generatePublic(formatted_public);

PrivateKey priv = kf.generatePrivate(formatted_private);

Если все, что вы хотите сделать, это использовать ECDSA в качестве алгоритма подписи, проверка идентична подписи с использованием методов verify вместо методов sign, а именно:

byte[] message_hash = // ...
byte[] candidate_message = // ...

PublicKey pub = // ...

Signature dsa = Signature.getInstance("SHA1withECDSA");

dsa.initVerify(pub);

dsa.update(candidate_message);

boolean success = dsa.verify(message_hash);
person initramfs    schedule 29.12.2014
comment
Спасибо за ответ, немного неверно на данный момент :) for(byte b : enc_key){ key_builder.append(String.format("%02x")); } вы можете забыть поставить b при добавлении строки, подобной этой: for(byte b : enc_key){ key_builder.append(String.format("%02x", b)); } Теперь я перехожу к проблеме проверки. - person Rhony; 29.12.2014
comment
@anIndonesian Ой, глупый я. Исправил в ответе. Значит, вы используете ECDSA только для проверки подписи? Если это так, то это точно такой же процесс, как и при подписании, только вы используете метод initVerify() и verify() вместо initSign() и sign(). - person initramfs; 29.12.2014
comment
У меня возникла ошибка, когда я пытаюсь проанализировать открытый и закрытый ключ, хочу сохранить этот поток в чистоте, пока я не отредактирую РЕШЕННУЮ проблему. Я вставляю код с информацией об ошибке в Загрузить закрытый и открытый ключ Извините, если я использую внешнюю ссылку :) - person Rhony; 29.12.2014
comment
Вау, еще один способ, как разобрать как открытый, так и закрытый ключ в массив байтов, я использую библиотеку надувного замка :) преобразовать byte[] enc_key = key.getEncoded();, заканчивающийся на String keyString = new String(Base64.encode(enc_key));, затем отправить keyString в базу данных, загрузить ключ с Base64.decode(keyString)затем отформатировать оба ключа , оно работает. Теперь я действительно иду к своему проверочному коду. Спасибо терминатор. - person Rhony; 29.12.2014
comment
извините, вы снова получили небольшую ошибку при проверке сообщения :) мы должны запустить метод обновления с исходным сообщением, потому что ori_messg находится в нулевом состоянии, прежде чем переходить к процессу проверки, код что-то вроде этого byte[] ori_message = \\ ... dsa.update(ori_message); тогда мы можем запустить проверку dsa.verify(message_hash); и теперь логическое значение возвращает true. Спасибо за ваш полезный ответ :), пожалуйста, обновите свой подтверждающий ответ. - person Rhony; 30.12.2014
comment
@anIndonesian Я как бы пропустил это, так как это было в основном то же самое, что и подписание, но я добавил его, чтобы было ясно. - person initramfs; 30.12.2014