导入和导出密钥
Importing and exporting keys
您好,我正在尝试为 RSA
、ECC
、AES GCM
和 ChaChaPoly1305
导入和导出(到和从字符串)public/private 键.
我正在使用充气城堡 1.59 来完成大部分工作。 RSA 我可以使用 java 原生支持的 KeyFactory
,所以这可能没问题。
但是,其他的好像不行。有谁知道这方面以前的工作?我正在寻找类似 wolfcrypt 的导入和导出功能的东西。
基本上我需要能够存储密钥然后重新创建它。
这是我的代码(我知道它很多,但它是我得到的)。
重要片段
public static void packRsaKey(Key key, KeyPair keyPair) {
key.toBuilder()
.addPrimaryKey(ByteString.copyFrom(keyPair.getPrivate().getEncoded()))
.addPublicKey(ByteString.copyFrom(keyPair.getPublic().getEncoded()))
.build();
}
public static void packECCKey(Key key, KeyPair keyPair) {
key.toBuilder()
.addPrimaryKey(ByteString.copyFrom(keyPair.getPrivate().getEncoded()))
.addPublicKey(ByteString.copyFrom(keyPair.getPublic().getEncoded()))
.build();
}
public static void packAESGCMKey(Key key, SecretKey secretKey, byte[] IV) {
key.toBuilder().setIv(ByteString.copyFrom(IV)).addPrimaryKey(ByteString.copyFrom(secretKey.getEncoded())).build();
}
public static void packChaChaPoly1305Key(Key key, SecretKey secretKey) {
key.toBuilder().addPrimaryKey(ByteString.copyFrom(secretKey.getEncoded()));
}
public static PrivateKey unpackRsaPrivateKey(Key key) throws InvalidKeySpecException, NoSuchAlgorithmException {
KeyFactory kf = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPublicKey(0).toByteArray());
return kf.generatePrivate(pkSpec);
}
public static PublicKey unpackRsaPublicKey(Key key) throws InvalidKeySpecException, NoSuchAlgorithmException {
KeyFactory kf = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPrimaryKey(0).toByteArray());
return kf.generatePublic(pkSpec);
}
public static SecretKey unpackAESGCMKey(Key key) {
return new SecretKeySpec(key.getPrimaryKey(0).toByteArray(), 0, key.getPrimaryKey(0).toByteArray().length, "AES");
}
public static SecretKey unpackChaChaPoly1305Key(Key key) {
return new SecretKeySpec(key.getPrimaryKey(0).toByteArray(), 0, key.getPrimaryKey(0).toByteArray().length, "ChaCha20");
}
public static PrivateKey unpackECCPrivateKey(Key key) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("EC");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPublicKey(0).toByteArray());
return kf.generatePrivate(pkSpec);
}
public static PublicKey unpackECCPublicKey(Key key) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("EC");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPrimaryKey(0).toByteArray());
return kf.generatePublic(pkSpec);
}
完整代码
package com.keiros.security.encryption;
import java.security.*;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import com.google.protobuf.ByteString;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import com.keiros.security.AsymmetricEncryptionClass.AsymmetricEncryption;
import com.keiros.security.KeyClass.Key;
import com.keiros.security.SymmetricEncryptionClass.SymmetricEncryption;
/**
* Helper class for encrypting strings.
*/
public class EncryptionHelper {
public static final int AES_KEY_SIZE = 32;
public static final int GCM_IV_LENGTH = 16;
public static final int GCM_TAG_LENGTH = 16;
public static boolean generateKey(Key key) {
if (key.hasSymmetricKeyType()) {
return generateSymmetricKey(key);
} else if (key.hasAsymmetricKeyType()) {
return generateAsymmetricKey(key);
}
return false;
}
public static boolean generateSymmetricKey(Key key) {
if (key.getSymmetricKeyType().getType() == SymmetricEncryption.Types.AES_GCM) {
try {
generateAESGCMKey(key);
return true;
} catch (Exception e) {
return false;
}
} else if (key.getSymmetricKeyType().getType() == SymmetricEncryption.Types.CHA_CHA_20_POLY_1305) {
try {
packChaChaPoly1305Key(key, generateChaChaPoly1305Key());
return true;
} catch (Exception e) {
return false;
}
}
return false;
}
public static SecretKey generateChaChaPoly1305Key() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("ChaCha20");
keyGenerator.init(32);
return keyGenerator.generateKey();
}
public static void generateAESGCMKey(Key key) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(AES_KEY_SIZE);
// Generate Key
byte[] IV = new byte[GCM_IV_LENGTH];
SecureRandom random = new SecureRandom();
random.nextBytes(IV);
SecretKey secretKey = keyGenerator.generateKey();
packAESGCMKey(key, secretKey, IV);
}
public static boolean generateAsymmetricKey(Key key) {
if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
try {
KeyPair keyPair = generateECCKeys();
packECCKey(key, keyPair);
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | NoSuchProviderException e) {
return false;
}
} else if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.SSH_2_RSA) {
try {
KeyPair keyPair = generateRsaKeys();
packRsaKey(key, keyPair);
return true;
} catch (NoSuchAlgorithmException e) {
return false;
}
}
return false;
}
public static KeyPair generateRsaKeys() throws NoSuchAlgorithmException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
return kpg.generateKeyPair();
}
public static KeyPair generateECCKeys() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
kpg.initialize(new ECGenParameterSpec("secp256r1"));
return kpg.generateKeyPair();
}
public static void packRsaKey(Key key, KeyPair keyPair) {
key.toBuilder()
.addPrimaryKey(ByteString.copyFrom(keyPair.getPrivate().getEncoded()))
.addPublicKey(ByteString.copyFrom(keyPair.getPublic().getEncoded()))
.build();
}
public static void packECCKey(Key key, KeyPair keyPair) {
key.toBuilder()
.addPrimaryKey(ByteString.copyFrom(keyPair.getPrivate().getEncoded()))
.addPublicKey(ByteString.copyFrom(keyPair.getPublic().getEncoded()))
.build();
}
public static void packAESGCMKey(Key key, SecretKey secretKey, byte[] IV) {
key.toBuilder().setIv(ByteString.copyFrom(IV)).addPrimaryKey(ByteString.copyFrom(secretKey.getEncoded())).build();
}
public static void packChaChaPoly1305Key(Key key, SecretKey secretKey) {
key.toBuilder().addPrimaryKey(ByteString.copyFrom(secretKey.getEncoded()));
}
public static PrivateKey unpackRsaPrivateKey(Key key) throws InvalidKeySpecException, NoSuchAlgorithmException {
KeyFactory kf = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPublicKey(0).toByteArray());
return kf.generatePrivate(pkSpec);
}
public static PublicKey unpackRsaPublicKey(Key key) throws InvalidKeySpecException, NoSuchAlgorithmException {
KeyFactory kf = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPrimaryKey(0).toByteArray());
return kf.generatePublic(pkSpec);
}
public static SecretKey unpackAESGCMKey(Key key) {
return new SecretKeySpec(key.getPrimaryKey(0).toByteArray(), 0, key.getPrimaryKey(0).toByteArray().length, "AES");
}
public static SecretKey unpackChaChaPoly1305Key(Key key) {
return new SecretKeySpec(key.getPrimaryKey(0).toByteArray(), 0, key.getPrimaryKey(0).toByteArray().length, "ChaCha20");
}
public static PrivateKey unpackECCPrivateKey(Key key) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("EC");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPublicKey(0).toByteArray());
return kf.generatePrivate(pkSpec);
}
public static PublicKey unpackECCPublicKey(Key key) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("EC");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPrimaryKey(0).toByteArray());
return kf.generatePublic(pkSpec);
}
public boolean encryptData(String in, StringBuilder out, Key key) {
if (key.hasAsymmetricKeyType()) {
if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.SSH_2_RSA) {
try {
out.append(encryptRsa(in.getBytes(), unpackRsaPublicKey(key)));
return true;
} catch (Exception e) {
return false;
}
}
} else if (key.hasSymmetricKeyType()) {
if (key.getSymmetricKeyType().getType() == SymmetricEncryption.Types.AES_GCM) {
try {
out.append(encryptAESGCM(in, key));
return true;
} catch (Exception e) {
return false;
}
} else if (key.getSymmetricKeyType().getType() == SymmetricEncryption.Types.CHA_CHA_20_POLY_1305) {
try {
out.append(encryptChaChaPoly1305(in, key));
return true;
} catch (Exception e) {
return false;
}
}
}
return false;
}
public boolean encryptData(String in, StringBuilder out, Key firstKey, Key secondKey) {
if (firstKey.hasAsymmetricKeyType() && firstKey.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
if (secondKey.hasAsymmetricKeyType() && secondKey.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
try {
out.append(encryptECC(in.getBytes(), (ECPrivateKey) unpackECCPrivateKey(firstKey),
(ECPublicKey) unpackECCPublicKey(secondKey)));
return true;
} catch (Exception e) {
return false;
}
}
}
return false;
}
public static String encryptRsa(byte[] data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return new String(cipher.doFinal(data));
}
// Source https://zhishenyong.com/ecc-asymmetric-encryption
public static String encryptECC(byte[] data, ECPrivateKey keyOnePrivateKey, ECPublicKey keyTwoPublicKey)
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException,
InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
// 1. Generate the pre-master shared secret
KeyAgreement ka = KeyAgreement.getInstance("ECDH", "BC");
ka.init(keyOnePrivateKey);
ka.doPhase(keyTwoPublicKey, true);
byte[] sharedSecret = ka.generateSecret();
// 2. (Optional) Hash the shared secret.
// Alternatively, you don't need to hash it.
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(sharedSecret);
byte[] digest = messageDigest.digest();
// 3. (Optional) Split up hashed shared secret into an initialization vector and a session key
// Alternatively, you can just use the shared secret as the session key and not use an iv.
int digestLength = digest.length;
byte[] iv = Arrays.copyOfRange(digest, 0, (digestLength + 1) / 2);
byte[] sessionKey = Arrays.copyOfRange(digest, (digestLength + 1) / 2, digestLength);
// 4. Create a secret key from the session key and initialize a cipher with the secret key
SecretKey secretKey = new SecretKeySpec(sessionKey, 0, sessionKey.length, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
// 5. Encrypt whatever message you want to send
return new String(cipher.doFinal(data));
}
public String encryptAESGCM(String in, Key key) throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
// Get Cipher Instance
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
// Create GCMParameterSpec
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, key.getIv().toByteArray());
// Initialize Cipher for ENCRYPT_MODE
cipher.init(Cipher.ENCRYPT_MODE, unpackAESGCMKey(key), gcmParameterSpec);
// Perform Encryption
byte[] cipherText = cipher.doFinal(in.getBytes());
return new String(cipherText);
}
public String encryptChaChaPoly1305(String in, Key key) throws NoSuchPaddingException, NoSuchAlgorithmException,
BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException {
byte[] nonceBytes = new byte[12];
// Get Cipher Instance
Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305/None/NoPadding");
// Create IvParamterSpec
AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(nonceBytes);
// Initialize Cipher for ENCRYPT_MODE
cipher.init(Cipher.ENCRYPT_MODE, unpackChaChaPoly1305Key(key), ivParameterSpec);
// Perform Encryption
byte[] cipherText = cipher.doFinal(in.getBytes());
return new String(cipherText);
}
public boolean decryptData(String in, StringBuilder out, Key key) {
if (key.hasAsymmetricKeyType()) {
if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.SSH_2_RSA) {
try {
out.append(decryptRsa(in, unpackRsaPrivateKey(key)));
return true;
} catch (Exception e) {
return false;
}
}
} else if (key.hasSymmetricKeyType()) {
if (key.getSymmetricKeyType().getType() == SymmetricEncryption.Types.AES_GCM) {
try {
out.append(decryptAESGCM(in, key));
return true;
} catch (Exception e) {
return false;
}
} else if (key.getSymmetricKeyType().getType() == SymmetricEncryption.Types.CHA_CHA_20_POLY_1305) {
try {
out.append(decryptChaChaPoly1305(in, key));
return true;
} catch (Exception e) {
return false;
}
}
}
return false;
}
public boolean decryptData(String in, StringBuilder out, Key firstKey, Key secondKey) {
if (firstKey.hasAsymmetricKeyType() && firstKey.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
if (secondKey.hasAsymmetricKeyType() && secondKey.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
try {
out.append(decryptECC(in.getBytes(), (ECPrivateKey) unpackECCPrivateKey(firstKey),
(ECPublicKey) unpackECCPublicKey(secondKey)));
return true;
} catch (Exception e) {
return false;
}
}
}
return false;
}
public static String decryptRsa(String encrypted, PrivateKey privateKey) throws InvalidCipherTextException,
NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException,
IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher.doFinal(encrypted.getBytes()));
}
// Source https://zhishenyong.com/ecc-asymmetric-encryption
public static String decryptECC(byte[] data, ECPrivateKey keyOnePrivateKey, ECPublicKey keyTwoPublicKey)
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException,
InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
// 1. Generate the pre-master shared secret
KeyAgreement ka = KeyAgreement.getInstance("ECDH", "BC");
ka.init(keyOnePrivateKey);
ka.doPhase(keyTwoPublicKey, true);
byte[] sharedSecret = ka.generateSecret();
// 2. (Optional) Hash the shared secret.
// Alternatively, you don't need to hash it.
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(sharedSecret);
byte[] digest = messageDigest.digest();
// 3. (Optional) Split up hashed shared secret into an initialization vector and a session key
// Alternatively, you can just use the shared secret as the session key and not use an iv.
int digestLength = digest.length;
byte[] iv = Arrays.copyOfRange(digest, 0, (digestLength + 1) / 2);
byte[] sessionKey = Arrays.copyOfRange(digest, (digestLength + 1) / 2, digestLength);
// 4. Create a secret key from the session key and initialize a cipher with the secret key
SecretKey secretKey = new SecretKeySpec(sessionKey, 0, sessionKey.length, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
// 5. Encrypt whatever message you want to send
return new String(cipher.doFinal(data));
}
public static String decryptAESGCM(String in, Key key) throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
// Get Cipher Instance
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
// Create GCMParameterSpec
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, key.getIv().toByteArray());
// Initialize Cipher for DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE, unpackAESGCMKey(key), gcmParameterSpec);
// Perform Decryption
byte[] decryptedText = cipher.doFinal(in.getBytes());
return new String(decryptedText);
}
public static String decryptChaChaPoly1305(String in, Key key) throws NoSuchPaddingException,
NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException,
IllegalBlockSizeException {
byte[] nonceBytes = new byte[12];
// Get Cipher Instance
Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305/None/NoPadding");
// Create IvParamterSpec
AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(nonceBytes);
// Initialize Cipher for DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE, unpackChaChaPoly1305Key(key), ivParameterSpec);
// Perform Decryption
byte[] decryptedText = cipher.doFinal(in.getBytes());
return new String(decryptedText);
}
public static boolean signData(String in, StringBuilder out, Key key) {
if (key.hasAsymmetricKeyType()) {
if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
} else if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.SSH_2_RSA) {
try {
out.append(signRsa(in, unpackRsaPrivateKey(key)));
} catch (Exception e) {
return false;
}
}
}
return false;
}
public static String signRsa(String in, PrivateKey privateKey)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Signature sig = Signature.getInstance("SHA1WithRSA");
sig.initSign(privateKey);
sig.update(in.getBytes());
return new String(sig.sign());
}
public static String signECC(String in, PrivateKey privateKey)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Signature sig = Signature.getInstance("SHA256withECDSA");
sig.initSign(privateKey);
sig.update(in.getBytes());
return new String(sig.sign());
}
public static boolean verifyData(String signature, String message, Key key) {
if (key.hasAsymmetricKeyType()) {
if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
try {
verifyECC(signature, message, unpackECCPublicKey(key));
} catch (Exception e) {
return false;
}
} else if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.SSH_2_RSA) {
try {
verifyRsa(signature, message, unpackRsaPublicKey(key));
} catch (Exception e) {
return false;
}
}
}
return false;
}
public static boolean verifyRsa(String signature, String message, PublicKey publicKey)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Signature sig = Signature.getInstance("SHA1WithRSA");
sig.initVerify(publicKey);
sig.update(message.getBytes());
return sig.verify(signature.getBytes());
}
public static boolean verifyECC(String signature, String message, PublicKey publicKey)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Signature sig = Signature.getInstance("SHA256withECDSA");
sig.initVerify(publicKey);
sig.update(message.getBytes());
return sig.verify(signature.getBytes());
}
}
这是原型参考。
密钥
message Key {
// Private key or the sole key.
// For ChaCha-Poly1305 the first key is the ChaCha the second is the Poly.
repeated bytes primary_key = 1;
// Public key (if this is asymmetric). Will almost always be one (no cases with multiple rn).
repeated bytes public_key = 2;
// What kind of key this is.
oneof key_type {
AsymmetricEncryption asymmetric_key_type = 3;
SymmetricEncryption symmetric_key_type = 4;
}
// The initialization vector if one is needed along with the key.
bytes iv = 5;
// An authentication tag if one is needed along with the key.
bytes auth_tag = 6;
// An authentication vector if one is needed along with the key.
bytes auth_vector = 7;
// Arbitrary additional data.
bytes arbitrary_additional_data = 8;
}
非对称加密
message AsymmetricEncryption {
// All the types of asymmetric encryption supported.
enum Types {
// The primary type within Keiros. Will be used for encrypting connections.
ECC = 0;
// A supported type that can be used only for signing.
ED25519 = 1;
// Useful for dealing with the keys that are generated by AWS.
SSH_2_RSA = 2;
}
Types type = 1;
// If there is a number of bits to go along with an encryption type. For example,
// SSH_2_RSA can be with 1024, 2048 etc...
// See https://security.stackexchange.com/questions/62247/should-i-use-more-than-2048-bits-in-my-ssh-2-rsa-key.
int64 bits_for_encryption_method = 2;
}
对称加密
message SymmetricEncryption {
// All the types of symmetric encryption supported.
enum Types {
// The primary type within Keiros. Useful for storage and for maintaining an encrypted
// connection.
AES_GCM = 0;
// A secondary type to allow stream decrypting -- just additional felxibility.
CHA_CHA_20_POLY_1305 = 1;
}
Types type = 1;
// If there is a number of bits to go along with an encryption type. For example,
// AES_GCM can use a "tag" of size 128, 120, 112, 104, or 96.
// See: https://en.wikipedia.org/wiki/Galois/Counter_Mode.
int64 bits_for_encryption_method = 2;
}
所以让我感到困惑的是,我在 C++ 中有相同的代码,但 wolfcrypt 将密钥编码为 RSA
的 DER
和 [=16= 的 X.963
格式].然后 AESGCM
和 ChaChaPoly1305
它们都是原始字节数组,而在这里它们不是。我只是想知道如果我在 java 中编码然后在 c++ 中解码是否有任何方法可以让它工作。我想一定有,因为 TLS 在 java 和 c++ 中工作。
描述 'DER' 含糊不清,但与您引用的对比相比,它可能意味着 RSA 密钥采用 PKCS1 aka RFC8017 et pred Appendix A.1 which like all ASN.1 data can be and for crypto often is encoded in DER. 'X.963' is clearly a mistake; the relevant standards for ECC crypto are X9.62 and X9.63, but the publickey format which indeed is not ASN.1/DER was defined by X9.62 and copied by X9.63, while the privatekey format was not standardized at all, but is often a raw octet string and not ASN.1/DER. (X.(number) standards are from the international treaty organization formerly called International Consultative Committee on Telephony and Telegraphy CCITT and now International Telecommunication Union Telecommunication Standardization Sector ITU-T; X9.(number) are from the USA private-sector financial-industry organization ANSI accredited standards committee (ASC) X9.) OTOH Java crypto encoding for private key is PKCS8 aka RFC5208 (unencrypted) 定义的 ASN.1 格式,其中添加了元数据。要将 Java 密钥转换为您的 'wolfcrypt' 显然想要的格式相当容易,只需提取与算法相关的元素,而相反,使用 [=61= 中的 'wolfcrypt' 密钥], 仅 Java 会非常困难,但添加 BouncyCastle 有很大帮助;关于这两个(或所有三个)的现有问题很多,我稍后会为您挖掘。
一些其他的,部分的,评论:
generateChaChaPoly1305Key, generateAESGCMKey: KeyGenerator.init(int)
取 bits 的数量,ChaCha20 应为 256,AES 应为 128、192 或 256。 (KeyPairGenerator
也是如此,您获得了 RSA 的权利。)不应使用 AES-GCM 的密钥生成 IV;在下面查看更多内容。
unpackRsaPrivateKey、unpackRsaPublicKey、unpackECCPrivateKey、unpackECCPublicKey:'PrivateKey' 方法使用 key.getPublicKey(),'PublicKey' 方法使用 key.getPrivateKey(),这似乎是倒退的。假设您更改 PrivateKey 方法以使用私钥,如上所述,私钥的 Java 编码是 PKCS8EncodedKeySpec
-- 而不是 X509EncodedKeySpec
,后者仅适用于 publickey.
unpackAESGCMKey,unpackChaChaPoly1305Key:使用整个byte[]
作为key,不需要指定, 0, array.length
,可以使用更简单的ctorSecretKeySpec(byte[], String algorithm)
.
encrypt*:您对密文执行 new String(byte[])
,在 decrypt* 方法中执行 (String_var).getBytes()
。 这不安全。 Java String
旨在保存 个字符 ,尽管加密仍然使用传统术语明文和密文,自从大约 1950 年以来,明文不再是必需的,密文实际上从来不是字符,而是任意位模式。尝试将这些位放入 Java String
然后取回它们通常会失败,尤其是在跨多个系统时(例如,在 A 上加密,在 B 上传输和解密,这是一种常见的用法)案件)。最好的办法是始终如一地处理它们 byte[]
;如果您必须 运行 通过无法处理任意位的方式发送它们,例如 SMS 或 Web (HTML),则需要以保留所有位的文本形式进行编码;常用的方法是十六进制(或十六进制)和 base64。
encryptAESGCM:尚不清楚key.getIV()
does/uses,但如果使用同一密钥重复多次加密的 IV 值,即 CATASTROPHIC ;即使是一次重复使用也会破坏所有真实性(攻击者可以伪造任何数据),并且根据您的数据从一次到少量重复使用(例如两次或十次)会破坏机密性(攻击者可以公开所谓的秘密数据)。
encryptChaChaPoly1305:这显然对每次加密都使用相同的随机数,全零;如果您完全重复使用密钥(这似乎是您的设计重点),这将以与 AES-GCM 相同的方式破坏所有安全性。
此时我放弃了。你应该扔掉这个设计,换成懂密码学的人的设计。
您好,我正在尝试为 RSA
、ECC
、AES GCM
和 ChaChaPoly1305
导入和导出(到和从字符串)public/private 键.
我正在使用充气城堡 1.59 来完成大部分工作。 RSA 我可以使用 java 原生支持的 KeyFactory
,所以这可能没问题。
但是,其他的好像不行。有谁知道这方面以前的工作?我正在寻找类似 wolfcrypt 的导入和导出功能的东西。
基本上我需要能够存储密钥然后重新创建它。
这是我的代码(我知道它很多,但它是我得到的)。
重要片段
public static void packRsaKey(Key key, KeyPair keyPair) {
key.toBuilder()
.addPrimaryKey(ByteString.copyFrom(keyPair.getPrivate().getEncoded()))
.addPublicKey(ByteString.copyFrom(keyPair.getPublic().getEncoded()))
.build();
}
public static void packECCKey(Key key, KeyPair keyPair) {
key.toBuilder()
.addPrimaryKey(ByteString.copyFrom(keyPair.getPrivate().getEncoded()))
.addPublicKey(ByteString.copyFrom(keyPair.getPublic().getEncoded()))
.build();
}
public static void packAESGCMKey(Key key, SecretKey secretKey, byte[] IV) {
key.toBuilder().setIv(ByteString.copyFrom(IV)).addPrimaryKey(ByteString.copyFrom(secretKey.getEncoded())).build();
}
public static void packChaChaPoly1305Key(Key key, SecretKey secretKey) {
key.toBuilder().addPrimaryKey(ByteString.copyFrom(secretKey.getEncoded()));
}
public static PrivateKey unpackRsaPrivateKey(Key key) throws InvalidKeySpecException, NoSuchAlgorithmException {
KeyFactory kf = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPublicKey(0).toByteArray());
return kf.generatePrivate(pkSpec);
}
public static PublicKey unpackRsaPublicKey(Key key) throws InvalidKeySpecException, NoSuchAlgorithmException {
KeyFactory kf = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPrimaryKey(0).toByteArray());
return kf.generatePublic(pkSpec);
}
public static SecretKey unpackAESGCMKey(Key key) {
return new SecretKeySpec(key.getPrimaryKey(0).toByteArray(), 0, key.getPrimaryKey(0).toByteArray().length, "AES");
}
public static SecretKey unpackChaChaPoly1305Key(Key key) {
return new SecretKeySpec(key.getPrimaryKey(0).toByteArray(), 0, key.getPrimaryKey(0).toByteArray().length, "ChaCha20");
}
public static PrivateKey unpackECCPrivateKey(Key key) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("EC");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPublicKey(0).toByteArray());
return kf.generatePrivate(pkSpec);
}
public static PublicKey unpackECCPublicKey(Key key) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("EC");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPrimaryKey(0).toByteArray());
return kf.generatePublic(pkSpec);
}
完整代码
package com.keiros.security.encryption;
import java.security.*;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import com.google.protobuf.ByteString;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import com.keiros.security.AsymmetricEncryptionClass.AsymmetricEncryption;
import com.keiros.security.KeyClass.Key;
import com.keiros.security.SymmetricEncryptionClass.SymmetricEncryption;
/**
* Helper class for encrypting strings.
*/
public class EncryptionHelper {
public static final int AES_KEY_SIZE = 32;
public static final int GCM_IV_LENGTH = 16;
public static final int GCM_TAG_LENGTH = 16;
public static boolean generateKey(Key key) {
if (key.hasSymmetricKeyType()) {
return generateSymmetricKey(key);
} else if (key.hasAsymmetricKeyType()) {
return generateAsymmetricKey(key);
}
return false;
}
public static boolean generateSymmetricKey(Key key) {
if (key.getSymmetricKeyType().getType() == SymmetricEncryption.Types.AES_GCM) {
try {
generateAESGCMKey(key);
return true;
} catch (Exception e) {
return false;
}
} else if (key.getSymmetricKeyType().getType() == SymmetricEncryption.Types.CHA_CHA_20_POLY_1305) {
try {
packChaChaPoly1305Key(key, generateChaChaPoly1305Key());
return true;
} catch (Exception e) {
return false;
}
}
return false;
}
public static SecretKey generateChaChaPoly1305Key() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("ChaCha20");
keyGenerator.init(32);
return keyGenerator.generateKey();
}
public static void generateAESGCMKey(Key key) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(AES_KEY_SIZE);
// Generate Key
byte[] IV = new byte[GCM_IV_LENGTH];
SecureRandom random = new SecureRandom();
random.nextBytes(IV);
SecretKey secretKey = keyGenerator.generateKey();
packAESGCMKey(key, secretKey, IV);
}
public static boolean generateAsymmetricKey(Key key) {
if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
try {
KeyPair keyPair = generateECCKeys();
packECCKey(key, keyPair);
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | NoSuchProviderException e) {
return false;
}
} else if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.SSH_2_RSA) {
try {
KeyPair keyPair = generateRsaKeys();
packRsaKey(key, keyPair);
return true;
} catch (NoSuchAlgorithmException e) {
return false;
}
}
return false;
}
public static KeyPair generateRsaKeys() throws NoSuchAlgorithmException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
return kpg.generateKeyPair();
}
public static KeyPair generateECCKeys() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
kpg.initialize(new ECGenParameterSpec("secp256r1"));
return kpg.generateKeyPair();
}
public static void packRsaKey(Key key, KeyPair keyPair) {
key.toBuilder()
.addPrimaryKey(ByteString.copyFrom(keyPair.getPrivate().getEncoded()))
.addPublicKey(ByteString.copyFrom(keyPair.getPublic().getEncoded()))
.build();
}
public static void packECCKey(Key key, KeyPair keyPair) {
key.toBuilder()
.addPrimaryKey(ByteString.copyFrom(keyPair.getPrivate().getEncoded()))
.addPublicKey(ByteString.copyFrom(keyPair.getPublic().getEncoded()))
.build();
}
public static void packAESGCMKey(Key key, SecretKey secretKey, byte[] IV) {
key.toBuilder().setIv(ByteString.copyFrom(IV)).addPrimaryKey(ByteString.copyFrom(secretKey.getEncoded())).build();
}
public static void packChaChaPoly1305Key(Key key, SecretKey secretKey) {
key.toBuilder().addPrimaryKey(ByteString.copyFrom(secretKey.getEncoded()));
}
public static PrivateKey unpackRsaPrivateKey(Key key) throws InvalidKeySpecException, NoSuchAlgorithmException {
KeyFactory kf = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPublicKey(0).toByteArray());
return kf.generatePrivate(pkSpec);
}
public static PublicKey unpackRsaPublicKey(Key key) throws InvalidKeySpecException, NoSuchAlgorithmException {
KeyFactory kf = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPrimaryKey(0).toByteArray());
return kf.generatePublic(pkSpec);
}
public static SecretKey unpackAESGCMKey(Key key) {
return new SecretKeySpec(key.getPrimaryKey(0).toByteArray(), 0, key.getPrimaryKey(0).toByteArray().length, "AES");
}
public static SecretKey unpackChaChaPoly1305Key(Key key) {
return new SecretKeySpec(key.getPrimaryKey(0).toByteArray(), 0, key.getPrimaryKey(0).toByteArray().length, "ChaCha20");
}
public static PrivateKey unpackECCPrivateKey(Key key) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("EC");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPublicKey(0).toByteArray());
return kf.generatePrivate(pkSpec);
}
public static PublicKey unpackECCPublicKey(Key key) throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("EC");
X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(key.getPrimaryKey(0).toByteArray());
return kf.generatePublic(pkSpec);
}
public boolean encryptData(String in, StringBuilder out, Key key) {
if (key.hasAsymmetricKeyType()) {
if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.SSH_2_RSA) {
try {
out.append(encryptRsa(in.getBytes(), unpackRsaPublicKey(key)));
return true;
} catch (Exception e) {
return false;
}
}
} else if (key.hasSymmetricKeyType()) {
if (key.getSymmetricKeyType().getType() == SymmetricEncryption.Types.AES_GCM) {
try {
out.append(encryptAESGCM(in, key));
return true;
} catch (Exception e) {
return false;
}
} else if (key.getSymmetricKeyType().getType() == SymmetricEncryption.Types.CHA_CHA_20_POLY_1305) {
try {
out.append(encryptChaChaPoly1305(in, key));
return true;
} catch (Exception e) {
return false;
}
}
}
return false;
}
public boolean encryptData(String in, StringBuilder out, Key firstKey, Key secondKey) {
if (firstKey.hasAsymmetricKeyType() && firstKey.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
if (secondKey.hasAsymmetricKeyType() && secondKey.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
try {
out.append(encryptECC(in.getBytes(), (ECPrivateKey) unpackECCPrivateKey(firstKey),
(ECPublicKey) unpackECCPublicKey(secondKey)));
return true;
} catch (Exception e) {
return false;
}
}
}
return false;
}
public static String encryptRsa(byte[] data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return new String(cipher.doFinal(data));
}
// Source https://zhishenyong.com/ecc-asymmetric-encryption
public static String encryptECC(byte[] data, ECPrivateKey keyOnePrivateKey, ECPublicKey keyTwoPublicKey)
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException,
InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
// 1. Generate the pre-master shared secret
KeyAgreement ka = KeyAgreement.getInstance("ECDH", "BC");
ka.init(keyOnePrivateKey);
ka.doPhase(keyTwoPublicKey, true);
byte[] sharedSecret = ka.generateSecret();
// 2. (Optional) Hash the shared secret.
// Alternatively, you don't need to hash it.
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(sharedSecret);
byte[] digest = messageDigest.digest();
// 3. (Optional) Split up hashed shared secret into an initialization vector and a session key
// Alternatively, you can just use the shared secret as the session key and not use an iv.
int digestLength = digest.length;
byte[] iv = Arrays.copyOfRange(digest, 0, (digestLength + 1) / 2);
byte[] sessionKey = Arrays.copyOfRange(digest, (digestLength + 1) / 2, digestLength);
// 4. Create a secret key from the session key and initialize a cipher with the secret key
SecretKey secretKey = new SecretKeySpec(sessionKey, 0, sessionKey.length, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
// 5. Encrypt whatever message you want to send
return new String(cipher.doFinal(data));
}
public String encryptAESGCM(String in, Key key) throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
// Get Cipher Instance
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
// Create GCMParameterSpec
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, key.getIv().toByteArray());
// Initialize Cipher for ENCRYPT_MODE
cipher.init(Cipher.ENCRYPT_MODE, unpackAESGCMKey(key), gcmParameterSpec);
// Perform Encryption
byte[] cipherText = cipher.doFinal(in.getBytes());
return new String(cipherText);
}
public String encryptChaChaPoly1305(String in, Key key) throws NoSuchPaddingException, NoSuchAlgorithmException,
BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException {
byte[] nonceBytes = new byte[12];
// Get Cipher Instance
Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305/None/NoPadding");
// Create IvParamterSpec
AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(nonceBytes);
// Initialize Cipher for ENCRYPT_MODE
cipher.init(Cipher.ENCRYPT_MODE, unpackChaChaPoly1305Key(key), ivParameterSpec);
// Perform Encryption
byte[] cipherText = cipher.doFinal(in.getBytes());
return new String(cipherText);
}
public boolean decryptData(String in, StringBuilder out, Key key) {
if (key.hasAsymmetricKeyType()) {
if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.SSH_2_RSA) {
try {
out.append(decryptRsa(in, unpackRsaPrivateKey(key)));
return true;
} catch (Exception e) {
return false;
}
}
} else if (key.hasSymmetricKeyType()) {
if (key.getSymmetricKeyType().getType() == SymmetricEncryption.Types.AES_GCM) {
try {
out.append(decryptAESGCM(in, key));
return true;
} catch (Exception e) {
return false;
}
} else if (key.getSymmetricKeyType().getType() == SymmetricEncryption.Types.CHA_CHA_20_POLY_1305) {
try {
out.append(decryptChaChaPoly1305(in, key));
return true;
} catch (Exception e) {
return false;
}
}
}
return false;
}
public boolean decryptData(String in, StringBuilder out, Key firstKey, Key secondKey) {
if (firstKey.hasAsymmetricKeyType() && firstKey.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
if (secondKey.hasAsymmetricKeyType() && secondKey.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
try {
out.append(decryptECC(in.getBytes(), (ECPrivateKey) unpackECCPrivateKey(firstKey),
(ECPublicKey) unpackECCPublicKey(secondKey)));
return true;
} catch (Exception e) {
return false;
}
}
}
return false;
}
public static String decryptRsa(String encrypted, PrivateKey privateKey) throws InvalidCipherTextException,
NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException,
IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher.doFinal(encrypted.getBytes()));
}
// Source https://zhishenyong.com/ecc-asymmetric-encryption
public static String decryptECC(byte[] data, ECPrivateKey keyOnePrivateKey, ECPublicKey keyTwoPublicKey)
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException,
InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
// 1. Generate the pre-master shared secret
KeyAgreement ka = KeyAgreement.getInstance("ECDH", "BC");
ka.init(keyOnePrivateKey);
ka.doPhase(keyTwoPublicKey, true);
byte[] sharedSecret = ka.generateSecret();
// 2. (Optional) Hash the shared secret.
// Alternatively, you don't need to hash it.
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(sharedSecret);
byte[] digest = messageDigest.digest();
// 3. (Optional) Split up hashed shared secret into an initialization vector and a session key
// Alternatively, you can just use the shared secret as the session key and not use an iv.
int digestLength = digest.length;
byte[] iv = Arrays.copyOfRange(digest, 0, (digestLength + 1) / 2);
byte[] sessionKey = Arrays.copyOfRange(digest, (digestLength + 1) / 2, digestLength);
// 4. Create a secret key from the session key and initialize a cipher with the secret key
SecretKey secretKey = new SecretKeySpec(sessionKey, 0, sessionKey.length, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
// 5. Encrypt whatever message you want to send
return new String(cipher.doFinal(data));
}
public static String decryptAESGCM(String in, Key key) throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
// Get Cipher Instance
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
// Create GCMParameterSpec
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, key.getIv().toByteArray());
// Initialize Cipher for DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE, unpackAESGCMKey(key), gcmParameterSpec);
// Perform Decryption
byte[] decryptedText = cipher.doFinal(in.getBytes());
return new String(decryptedText);
}
public static String decryptChaChaPoly1305(String in, Key key) throws NoSuchPaddingException,
NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException,
IllegalBlockSizeException {
byte[] nonceBytes = new byte[12];
// Get Cipher Instance
Cipher cipher = Cipher.getInstance("ChaCha20-Poly1305/None/NoPadding");
// Create IvParamterSpec
AlgorithmParameterSpec ivParameterSpec = new IvParameterSpec(nonceBytes);
// Initialize Cipher for DECRYPT_MODE
cipher.init(Cipher.DECRYPT_MODE, unpackChaChaPoly1305Key(key), ivParameterSpec);
// Perform Decryption
byte[] decryptedText = cipher.doFinal(in.getBytes());
return new String(decryptedText);
}
public static boolean signData(String in, StringBuilder out, Key key) {
if (key.hasAsymmetricKeyType()) {
if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
} else if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.SSH_2_RSA) {
try {
out.append(signRsa(in, unpackRsaPrivateKey(key)));
} catch (Exception e) {
return false;
}
}
}
return false;
}
public static String signRsa(String in, PrivateKey privateKey)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Signature sig = Signature.getInstance("SHA1WithRSA");
sig.initSign(privateKey);
sig.update(in.getBytes());
return new String(sig.sign());
}
public static String signECC(String in, PrivateKey privateKey)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Signature sig = Signature.getInstance("SHA256withECDSA");
sig.initSign(privateKey);
sig.update(in.getBytes());
return new String(sig.sign());
}
public static boolean verifyData(String signature, String message, Key key) {
if (key.hasAsymmetricKeyType()) {
if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.ECC) {
try {
verifyECC(signature, message, unpackECCPublicKey(key));
} catch (Exception e) {
return false;
}
} else if (key.getAsymmetricKeyType().getType() == AsymmetricEncryption.Types.SSH_2_RSA) {
try {
verifyRsa(signature, message, unpackRsaPublicKey(key));
} catch (Exception e) {
return false;
}
}
}
return false;
}
public static boolean verifyRsa(String signature, String message, PublicKey publicKey)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Signature sig = Signature.getInstance("SHA1WithRSA");
sig.initVerify(publicKey);
sig.update(message.getBytes());
return sig.verify(signature.getBytes());
}
public static boolean verifyECC(String signature, String message, PublicKey publicKey)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Signature sig = Signature.getInstance("SHA256withECDSA");
sig.initVerify(publicKey);
sig.update(message.getBytes());
return sig.verify(signature.getBytes());
}
}
这是原型参考。
密钥
message Key {
// Private key or the sole key.
// For ChaCha-Poly1305 the first key is the ChaCha the second is the Poly.
repeated bytes primary_key = 1;
// Public key (if this is asymmetric). Will almost always be one (no cases with multiple rn).
repeated bytes public_key = 2;
// What kind of key this is.
oneof key_type {
AsymmetricEncryption asymmetric_key_type = 3;
SymmetricEncryption symmetric_key_type = 4;
}
// The initialization vector if one is needed along with the key.
bytes iv = 5;
// An authentication tag if one is needed along with the key.
bytes auth_tag = 6;
// An authentication vector if one is needed along with the key.
bytes auth_vector = 7;
// Arbitrary additional data.
bytes arbitrary_additional_data = 8;
}
非对称加密
message AsymmetricEncryption {
// All the types of asymmetric encryption supported.
enum Types {
// The primary type within Keiros. Will be used for encrypting connections.
ECC = 0;
// A supported type that can be used only for signing.
ED25519 = 1;
// Useful for dealing with the keys that are generated by AWS.
SSH_2_RSA = 2;
}
Types type = 1;
// If there is a number of bits to go along with an encryption type. For example,
// SSH_2_RSA can be with 1024, 2048 etc...
// See https://security.stackexchange.com/questions/62247/should-i-use-more-than-2048-bits-in-my-ssh-2-rsa-key.
int64 bits_for_encryption_method = 2;
}
对称加密
message SymmetricEncryption {
// All the types of symmetric encryption supported.
enum Types {
// The primary type within Keiros. Useful for storage and for maintaining an encrypted
// connection.
AES_GCM = 0;
// A secondary type to allow stream decrypting -- just additional felxibility.
CHA_CHA_20_POLY_1305 = 1;
}
Types type = 1;
// If there is a number of bits to go along with an encryption type. For example,
// AES_GCM can use a "tag" of size 128, 120, 112, 104, or 96.
// See: https://en.wikipedia.org/wiki/Galois/Counter_Mode.
int64 bits_for_encryption_method = 2;
}
所以让我感到困惑的是,我在 C++ 中有相同的代码,但 wolfcrypt 将密钥编码为 RSA
的 DER
和 [=16= 的 X.963
格式].然后 AESGCM
和 ChaChaPoly1305
它们都是原始字节数组,而在这里它们不是。我只是想知道如果我在 java 中编码然后在 c++ 中解码是否有任何方法可以让它工作。我想一定有,因为 TLS 在 java 和 c++ 中工作。
描述 'DER' 含糊不清,但与您引用的对比相比,它可能意味着 RSA 密钥采用 PKCS1 aka RFC8017 et pred Appendix A.1 which like all ASN.1 data can be and for crypto often is encoded in DER. 'X.963' is clearly a mistake; the relevant standards for ECC crypto are X9.62 and X9.63, but the publickey format which indeed is not ASN.1/DER was defined by X9.62 and copied by X9.63, while the privatekey format was not standardized at all, but is often a raw octet string and not ASN.1/DER. (X.(number) standards are from the international treaty organization formerly called International Consultative Committee on Telephony and Telegraphy CCITT and now International Telecommunication Union Telecommunication Standardization Sector ITU-T; X9.(number) are from the USA private-sector financial-industry organization ANSI accredited standards committee (ASC) X9.) OTOH Java crypto encoding for private key is PKCS8 aka RFC5208 (unencrypted) 定义的 ASN.1 格式,其中添加了元数据。要将 Java 密钥转换为您的 'wolfcrypt' 显然想要的格式相当容易,只需提取与算法相关的元素,而相反,使用 [=61= 中的 'wolfcrypt' 密钥], 仅 Java 会非常困难,但添加 BouncyCastle 有很大帮助;关于这两个(或所有三个)的现有问题很多,我稍后会为您挖掘。
一些其他的,部分的,评论:
generateChaChaPoly1305Key, generateAESGCMKey: KeyGenerator.init(int)
取 bits 的数量,ChaCha20 应为 256,AES 应为 128、192 或 256。 (KeyPairGenerator
也是如此,您获得了 RSA 的权利。)不应使用 AES-GCM 的密钥生成 IV;在下面查看更多内容。
unpackRsaPrivateKey、unpackRsaPublicKey、unpackECCPrivateKey、unpackECCPublicKey:'PrivateKey' 方法使用 key.getPublicKey(),'PublicKey' 方法使用 key.getPrivateKey(),这似乎是倒退的。假设您更改 PrivateKey 方法以使用私钥,如上所述,私钥的 Java 编码是 PKCS8EncodedKeySpec
-- 而不是 X509EncodedKeySpec
,后者仅适用于 publickey.
unpackAESGCMKey,unpackChaChaPoly1305Key:使用整个byte[]
作为key,不需要指定, 0, array.length
,可以使用更简单的ctorSecretKeySpec(byte[], String algorithm)
.
encrypt*:您对密文执行 new String(byte[])
,在 decrypt* 方法中执行 (String_var).getBytes()
。 这不安全。 Java String
旨在保存 个字符 ,尽管加密仍然使用传统术语明文和密文,自从大约 1950 年以来,明文不再是必需的,密文实际上从来不是字符,而是任意位模式。尝试将这些位放入 Java String
然后取回它们通常会失败,尤其是在跨多个系统时(例如,在 A 上加密,在 B 上传输和解密,这是一种常见的用法)案件)。最好的办法是始终如一地处理它们 byte[]
;如果您必须 运行 通过无法处理任意位的方式发送它们,例如 SMS 或 Web (HTML),则需要以保留所有位的文本形式进行编码;常用的方法是十六进制(或十六进制)和 base64。
encryptAESGCM:尚不清楚key.getIV()
does/uses,但如果使用同一密钥重复多次加密的 IV 值,即 CATASTROPHIC ;即使是一次重复使用也会破坏所有真实性(攻击者可以伪造任何数据),并且根据您的数据从一次到少量重复使用(例如两次或十次)会破坏机密性(攻击者可以公开所谓的秘密数据)。
encryptChaChaPoly1305:这显然对每次加密都使用相同的随机数,全零;如果您完全重复使用密钥(这似乎是您的设计重点),这将以与 AES-GCM 相同的方式破坏所有安全性。
此时我放弃了。你应该扔掉这个设计,换成懂密码学的人的设计。