تشفير Java غير المتماثل: الطريقة المفضلة لتخزين المفاتيح العامة/الخاصة

StackOverflow https://stackoverflow.com/questions/3441501

سؤال

يولد هذا الرمز زوجًا من المفاتيح العامة/الخاصة:

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair keypair = keyGen.genKeyPair();
PrivateKey privateKey = keypair.getPrivate();
PublicKey publicKey = keypair.getPublic();

ما أود معرفته هو كيف تقوم عادة بتخزين المفتاح العام:

الخيار 1: تخزين البايتات

byte[] privateKeyBytes = privateKey.getEncoded();
byte[] publicKeyBytes = publicKey.getEncoded();
// ... write to file

// convert bytes back to public/private keys
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

ما لا يعجبني هو ربط الرمز بالتطبيقات الملموسة مثل PKCS8EncodedKeySpec و X509EncodedKeySpec.

الخيار 2: قم بتخزين المعامل والأسس

KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(publicKey, RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(privateKey,RSAPrivateKeySpec.class);

// store modulus and exponent as BigIntegers
BigInteger modulus = pub.getModulus());
BigInteger exponent = pub.getPublicExponent());
// ... write to file

// recreate public key (the same applies to the private key)
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);

الخيار الثاني أسهل في التنفيذ ، لكنني لا أعرف ما إذا كان قد يكون أقل أداء.

أي نصيحة؟

هل كانت مفيدة؟

المحلول

في تطبيقاتنا ، نقوم بتخزين المفاتيح العامة والخاصة بتنسيق DER حتى يمكن استخدامها والتلاعب بها خارج Java بسهولة أكبر. في حالتنا ، لا تحتوي المفاتيح الخاصة على كلمات مرور عليها.

لتحويل المفتاح الخاص إلى شيء أكثر سهولة في جافا:

openssl pkcs8 -topk8 -nocrypt -in key.pem -inform PEM -out key.der -outform DER

ثم يمكنك الحصول على مفتاح خاص RSA مباشرة بواسطة:

public static RSAPrivateKey getPrivateKey(File privateKeyFile) throws IOException, GeneralSecurityException {
    byte[] keyBytes = new byte[(int)privateKeyFile.length()];
    FileInputStream fis = new FileInputStream(privateKeyFile);
    fis.read(keyBytes);
    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(spec);
    return privKey;
}

المفتاح العام متشابه:

openssl rsa -in private.pem -pubout -outform DER -out public.der

وقراءته:

public static RSAPublicKey getPublicKey(File publicKeyFile) throws IOException, GeneralSecurityException {
    byte[] keyBytes = new byte[(int)publicKeyFile.length()];
    FileInputStream fis = new FileInputStream(publicKeyFile);
    fis.read(keyBytes);
    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(keyBytes);
    KeyFactory factory = KeyFactory.getInstance("RSA");
    RSAPublicKey pubKey = (RSAPublicKey)factory.generatePublic(publicKeySpec);
    return pubKey;
}

يقوم العديد من الأشخاص بتخزين keystores. لأغراضنا ، كنا بحاجة إلى مشاركة نفس المفتاح عبر تطبيقات متعددة بعدة لغات مختلفة ، ولم نرغب في تكرار الملفات على القرص.

في كلتا الحالتين ، لا ينبغي أن يكون الأداء مصدر قلق كبير ، لأنك من المحتمل أن تخزن تلك المفاتيح في نوع من المفرد أو ذاكرة التخزين المؤقت بدلاً من تجديدها في كل مرة.

نصائح أخرى

أنت تقوم بالفعل بتخزين البايتات في كلتا الحالتين سواء أدركت ذلك أم لا. أفترض أن الإجابة الصحيحة تم التلميح إليها في إجابة M. Carr Brian ، والتي تتمثل في تخزين الكائن ذي المستوى الأعلى بأكثر أشكاله الطبيعية. في حالة المفاتيح العامة ، تكون الخيارات الواضحة بمثابة هيكل PKCS#1 rsapublickey asn.1 ، مشفرة der ، أو كهيكل x509 thisppublickeyinfo asn.1 ، der-encoded. هذا الأخير هو ما تقدمه لك مقدمو الشمس ، وهو ما يدعمه Sun Class X509EncodedKeySpec. وبالمثل ، يدعم PKCS8ENCODEDEKYSPEC تنسيقًا رئيسيًا خاصًا. كلا التنسيقين هما معايير ، ويدعمها OpenSSL على سبيل المثال. تميل الشمس - تميل :( - لدعم المعايير الحالية بدلاً من تحديدها.

إذا كنت ترغب في تحديد تنسيق لتخزين المفاتيح ، فسوف أختار تنسيقًا قابل للاستعادة بحيث لا ينكسر عندما تريد تغيير التشفير (عندما يضعف القديم على سبيل المثال).

لذلك أود تخزين البايتات المشفرة على أنها BASE64 ، مع سلسلة تصف التنسيق ، "RSA" ربما.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top