2016-11-01 3 views
1

Я реализовал создание пары ключей RSA в Java. Я генерирую открытый и закрытый ключ, а затем сохраняю их как значения BigInteger в файлах.Java: Как использовать кодировку PKCS # 1 для файлов

Я должен использовать кодировку PKCS # 1 для этих файлов. Я относительно новичок в криптографии. Может ли кто-нибудь дать мне простой пример того, как это можно сделать?


Примечания: Я не могу использовать какие-либо внешние библиотеки Java.

Для полноты картины, я отправляю код, используемый для создания общественных/частных ключей:

private void generateKeys(int bits, int certainty, 
           String publicKeyFile, String secretKeyFile) throws IOException { 
    p = new BigInteger(bits, certainty, new Random()); 

    do 
     q = new BigInteger(bits, certainty, new Random()); 
    while (!p.gcd(q).equals(BigInteger.valueOf(1))); 

    n = p.multiply(q); 
    BigInteger phiN = p.subtract(BigInteger.valueOf(1)). 
      multiply(q.subtract(BigInteger.valueOf(1))); 

    do 
     e = new BigInteger(bits, new Random()); 
    while (!e.gcd(phiN).equals(new BigInteger("1"))); 

    BigInteger d = e.modInverse(phiN); 
    dp = d.mod((p.subtract(BigInteger.valueOf(1)))); 
    dq = d.mod((q.subtract(BigInteger.valueOf(1)))); 
    qinv = q.modInverse(p); 

    write(secretKeyFile, n + "\n" + e + "\n" + d + "\n" + p + "\n" + q + "\n" + 
      dp + "\n" + dq + "\n" + qinv); 

    write(publicKeyFile, n + "\n" + e); 

    System.out.println("n = " + n.toString(16)); 
    System.out.println("e = " + e.toString(16)); 
    System.out.println("d = " + d.toString(16)); 
    System.out.println("p = " + p.toString(16)); 
    System.out.println("q = " + q.toString(16)); 
    System.out.println("dp = " + dp.toString(16)); 
    System.out.println("dq = " + dq.toString(16)); 
    System.out.println("qinv = " + qinv.toString(16)); 
} 
+1

Вы уверены, что не имеете в виду PKCS # 11? – EJP

+0

Нет, его PKCS # 1. Отличается ли он от ASN1, RFC3447? –

+0

@EJP, Любые мысли ?? –

ответ

1

ОК, так что вы должны реализовать структуры в PKCS # 1, следующий код должен работать (предупреждение, в основном не тестировалась, но ASN.1 разбирает).

package nl.owlstead.stackoverflow; 

import java.io.ByteArrayOutputStream; 
import java.io.DataOutputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.OutputStream; 
import java.math.BigInteger; 
import java.util.Random; 

/** 
* Generates a key pair and then saves the key to PKCS#1 format on disk. 
* <p> 
* From <a href="https://tools.ietf.org/html/rfc3447#appendix-C">RFC 3441, 
* Appendix C</a>: 
* 
* <pre> 
* RSAPublicKey ::= SEQUENCE { 
*  modulus   INTEGER, -- n 
*  publicExponent INTEGER -- e 
* } 
* 
* -- 
* -- Representation of RSA private key with information for the CRT 
* -- algorithm. 
* -- 
* RSAPrivateKey ::= SEQUENCE { 
*  version   Version, 
*  modulus   INTEGER, -- n 
*  publicExponent INTEGER, -- e 
*  privateExponent INTEGER, -- d 
*  prime1   INTEGER, -- p 
*  prime2   INTEGER, -- q 
*  exponent1   INTEGER, -- d mod (p-1) 
*  exponent2   INTEGER, -- d mod (q-1) 
*  coefficient  INTEGER, -- (inverse of q) mod p 
*  otherPrimeInfos OtherPrimeInfos OPTIONAL 
* } 
* </pre> 
* 
* @author owlstead 
* 
*/ 
public class SimplePKCS1 { 

    private static final byte SEQUENCE_TAG = 0x30; 
    private static final byte INTEGER_TAG = 0x02; 

    private static void writePublicKeyToPKCS1(
      String publicKeyFile, 
      BigInteger n, BigInteger e) { 

     try { 
      ByteArrayOutputStream integerStream = 
        new ByteArrayOutputStream(); 
      encodeInteger(integerStream, n); 
      encodeInteger(integerStream, e); 
      byte[] encodedIntegers = integerStream.toByteArray(); 

      try (FileOutputStream fos = 
        new FileOutputStream(publicKeyFile)) { 
       fos.write(SEQUENCE_TAG); 
       encodeLength(fos, encodedIntegers.length); 
       fos.write(encodedIntegers); 
      } 
     } catch (IOException ex) { 
      throw new IllegalStateException("Somaliland?"); 
     } 
    } 

    private static void writePrivateKeyToPKCS1(
      String secretKeyFile, 
      BigInteger n, BigInteger e, BigInteger d, 
      BigInteger p, BigInteger q, 
      BigInteger dp, BigInteger dq, 
      BigInteger qinv) { 
     try { 
      ByteArrayOutputStream integerStream = 
        new ByteArrayOutputStream(); 
      encodeInteger(integerStream, n); 
      encodeInteger(integerStream, e); 
      encodeInteger(integerStream, d); 
      encodeInteger(integerStream, p); 
      encodeInteger(integerStream, q); 
      encodeInteger(integerStream, dp); 
      encodeInteger(integerStream, dq); 
      encodeInteger(integerStream, qinv); 
      byte[] encodedIntegers = integerStream.toByteArray(); 

      try (FileOutputStream fos = new FileOutputStream(secretKeyFile)) { 
       fos.write(SEQUENCE_TAG); 
       encodeLength(fos, encodedIntegers.length); 
       fos.write(encodedIntegers); 
      } 
     } catch (IOException ex) { 
      throw new IllegalStateException("Somaliland?"); 
     } 
    } 

    /** 
    * Writes an explicit DER encoded integer (tag, length and value). 
    * 
    * @param os 
    *   the stream to write to 
    * @param i 
    *   the integer to write 
    * @throws IOException 
    *    any IOException thrown by the output stream 
    */ 
    private static void encodeInteger(OutputStream os, BigInteger i) 
      throws IOException { 
     os.write(INTEGER_TAG); 
     byte[] encodedInteger = i.toByteArray(); 
     encodeLength(os, encodedInteger.length); 
     os.write(encodedInteger); 
    } 

    /** 
    * Encodes a length in DER format (minimum, definite BER size). 
    * 
    * @param os 
    *   the stream to write to 
    * @param length 
    *   the length of the value to write 
    * @throws IOException 
    *    any IOException thrown by the output stream 
    */ 
    private static void encodeLength(OutputStream os, int length) 
      throws IOException { 
     final DataOutputStream dos = new DataOutputStream(os); 
     if (length < (1 << (Byte.SIZE - 1))) { 
      dos.write(length); 
     } else if (length < (1 << Byte.SIZE)) { 
      dos.write(0x81); 
      dos.write(length); 
     } else if (length < (1 << Short.SIZE)) { // let's hope so :) 
      dos.write(0x82); 
      dos.writeShort(length); 
     } else { 
      throw new IllegalArgumentException(
        "Cannot handle integers over 65535 bytes in size"); 
     } 
    } 

    /* 
    * === the existing code and calls to the required functionality === 
    */ 

    private static void generateAndWriteKeys(
      int bits, int certainty, 
      String publicKeyFile, String secretKeyFile) { 
     BigInteger p = new BigInteger(bits, certainty, new Random()); 

     BigInteger q; 
     do { 
      q = new BigInteger(bits, certainty, new Random()); 
     } while (!p.gcd(q).equals(BigInteger.valueOf(1))); 

     BigInteger n = p.multiply(q); 
     BigInteger phiN = p.subtract(BigInteger.valueOf(1)).multiply(
       q.subtract(BigInteger.valueOf(1))); 

     BigInteger e; 
     do { 
      e = new BigInteger(bits, new Random()); 
     } while (!e.gcd(phiN).equals(new BigInteger("1"))); 

     BigInteger d = e.modInverse(phiN); 
     BigInteger dp = d.mod((p.subtract(BigInteger.valueOf(1)))); 
     BigInteger dq = d.mod((q.subtract(BigInteger.valueOf(1)))); 
     BigInteger qinv = q.modInverse(p); 

     writePublicKeyToPKCS1(publicKeyFile, n, e); 
     writePrivateKeyToPKCS1(secretKeyFile, n, e, d, p, q, dp, dq, qinv); 

    } 

    public static void main(String[] args) { 
     generateAndWriteKeys(1024, Integer.MAX_VALUE, args[0], args[1]); 
    } 
} 

следующие методы показывают, как разобрать вещи обратно в

private static PublicKey readPublicKeyFromPKCS1(
     String publicKeyFile) { 

    try { 
     try (FileInputStream fis = 
       new FileInputStream(publicKeyFile)) { 

      byte sequence = read(fis); 
      if (sequence != SEQUENCE_TAG) { 
       throw new IOException("No sequence tag found"); 
      } 


      int length = decodeLength(fis); 
      // use a CountingInputStream to check if the length of the SEQUENCE is correct 

      BigInteger n = decodeInteger(fis); 
      BigInteger e = decodeInteger(fis); 

      return new PublicKey(n, e); 
     } 
    } catch (IOException ex) { 
     throw new IllegalStateException("Somaliland?", ex); 
    } 
} 

private static BigInteger decodeInteger(InputStream is) throws IOException { 
    byte integer = read(is); 
    if (integer != INTEGER_TAG) { 
     throw new IOException("No integer tag found"); 
    } 
    int size = decodeLength(is); 
    ByteArrayOutputStream integerValueStream = new ByteArrayOutputStream(size); 
    for (int i = 0; i < size; i++) { 
     byte b = read(is); 
     integerValueStream.write(b); 
    } 
    byte[] integerValue = integerValueStream.toByteArray(); 
    return new BigInteger(integerValue); 
} 

private static int decodeLength(InputStream is) throws IOException { 
    int firstByte = read(is) & 0xFF; 
    if (firstByte < 0x80) { 
     return firstByte; 
    } 

    switch (firstByte) { 
    case 0x80: 
     throw new IOException("Invalid length"); 
    case 0x81: 
     byte length = read(is); 
     return length & 0xFF; 
    case 0x82: 
     int lengthHi = read(is) & 0xFF; 
     int lengthLo = read(is) & 0xFF; 
     return (int) (lengthHi << Byte.SIZE + lengthLo); 
    default: 
     throw new IOException("Length encoding unsupported"); 
    } 
} 

private static byte read(InputStream is) throws IOException { 
    int x = is.read(); 
    if (x == -1) { 
     throw new IOException("End of file reached before structure could be read"); 
    } 
    return (byte) x; 
} 

PublicKey это просто контейнер данных с n и e поле.

+0

Спасибо @Maarteen. Но предположим, что я хочу получить значение n, e, d ... для шифрования/дешифрования, как это сделать? –

+1

Вы снова разбираете структуры. Я имею в виду кодирование и декодирование, не так ли? Однако я оставлю это как упражнение. Вы можете видеть, как строятся структуры, поэтому имейте удовольствие, читая их. –

+1

Мех, я опубликую что-нибудь, чтобы разобрать открытый ключ, когда я вернусь домой. –

 Смежные вопросы

  • Нет связанных вопросов^_^