压缩 java 中的 RSA 编码值
Compress RSA Encoded value in java
我有一个 java class,其中对传递的 String
值执行 RSA Encryption
。获取冗长的编码值。
输入字符串:justin
RSA 编码值作为输出:.eJwdy00OwiAQBtC7zFqS4Ufg8zLNUIaGDZjaxoXx7ja-_fvQc751X3qlB2Wp4kKCU47BZy4A7pa9uuitqNKN5t63PuToY1vO87-wri02gSlSiwloMKhcDZxoSClDAl-zj9exjHkFy0zfH5pUI3w.YfvMdQ.GcmMQuY3BN33JATAfFB3ZyeXO8U
RSA 加密代码:
String username="justin";
String encrypteduser=getEncryptedPassword(username);
System.out.println("encrypteduser! " + encrypteduser);
public String getEncryptedPassword(String plainTextPassword)
{
String result="";
try {
result= getEncryptedPasswd(plainTextPassword);
log.info("result: " + result);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
protected String getEncryptedPasswd(String plain) throws Exception {
try {
InputStream is = new ByteArrayInputStream(getCertificate().getBytes());
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
PublicKey pubKey = cert.getPublicKey();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte cipherBytes[] = cipher.doFinal(plain.getBytes());
String encrypted = Base64.getEncoder().encodeToString(cipherBytes);
return encrypted;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
private String getCertificate() {
String certStr = "-----BEGIN CERTIFICATE-----\n"
+ "MIIGgDCCBWigAwIBAgIKMvrulAAAAARG5DANBgkqhkiG9w0BAQsFADBbMRMwEQYK"
+ "CZImiZPyLGQBGRYDbmV0MRkwFwYKCZIm"
+ "-----END CERTIFICATE-----";
return certStr;
}
我的目标是将 RSA 编码值压缩为缩短值。
我希望转换后(RSA
到 UTF-8
)会得到一些缩短的值。
注意:如果 UTF-8
转换没有帮助,则寻找对编码值的一些压缩。
在 java 8 中有什么方法可以做到这一点吗?
您的密文似乎已经采用 UTF-8 编码。它是 base-64 编码的; base-64 仅使用 US-ASCII 个字符,US-ASCII 编码是 UTF-8 编码的子集。
我相信你不是在要求你想要什么。你想要更短的密文吗?如果是这样,UTF-8 与此无关。
RSA 密文的长度等于 RSA 密钥的模数。 (这也对纯文本长度施加了上限。)根据安全要求选择密钥大小。现在 3072 位或 2048 位是典型的。对于这些密钥长度,通常支持的最短文本编码分别为 512 或 342 个字符。 (有一些不太常见的 binary-to-text 编码可以分别将其减少到 480 或 320 个字符,但它们会在 URL 和其他上下文中引起问题,因为它们使用更多的符号。)
如果您想要更短的密文,请使用不同的加密算法。对于 public 密钥加密,椭圆曲线算法使用较短的密钥提供相同级别的安全性(无论如何,据我们所知)。这意味着您的纯文本和密文将更短。或者,也许对称算法可能适用于您的方案。根据模式,这些可以输出与明文长度相同的密文(尽管这会泄露有关明文的信息并可能危及安全性)。
加密运算产生的字符串字节可以具有任何序列中的任何值。我不知道有任何 single-byte 字符编码将每个值映射到一个字符,也没有 multi-byte 字符编码将每个字节序列映射到一个字符。将这些事实放在一起,您将始终需要像 base-64 编码这样的东西来将您的密文转换为实际字符。因此,您的文本平均会长 33%。
为了与 7 位字符代码 US-ASCII 在很大程度上兼容,UTF-8 也仅使用低 7 位对单字节字符进行编码。这意味着使用 UTF-8 和 ASCII 中的单个字节存在相同的 95 个可打印字符。移动到两个或更高字节的 UTF-8 编码需要 更多 space,所以这根本没有用。
所以基本上您可以使用任何现有的 ASCII 文本编码。您已经在使用已经非常密集的 base 64。但是,您可以例如也使用 Z85 可以包含更多的二进制数据,缺点是它不是二的幂,所以编码/解码(或基本转换)会有些棘手和昂贵。此外,base 85 编码仅对 base 64 的 6 位中的每个字符编码大约 6.41 位,因此 return 是最小的(大约 6.82%)。
执行转换时应始终指明编码。但是,如前所述,UTF-8 完全兼容 Base 64 和 Z85 的 ASCII。所以我会指出编码 StandardCharsets.US_ASCII
,而不是 UTF_8
,因为其他人无疑会建议。
可以肯定的是:如果您能够处理字节,那么无编码总是比执行一些转换为效率较低的表示更好。
创建更小密文的唯一真正方法是查看混合加密。仅使用 RSA 加密或派生对称密钥并使用它来加密诸如密码之类的小字符串并不是真正可行的。 RSA 密文由(大部分)随机字节组成,因此至少平均而言不可能进一步压缩这些字节。
但是,您可以查看 ECIES,可能使用 压缩 临时 public 密钥。然后,您可以为 public 密钥(例如曲线类型 P256,强度为 128 位)使用 33 个字节,并为密码本身使用特定的最大密码大小,例如使用AES-CTR。您应该对密码使用静态大小的编码,否则可能会泄露密码大小。
我有一个 java class,其中对传递的 String
值执行 RSA Encryption
。获取冗长的编码值。
输入字符串:justin
RSA 编码值作为输出:.eJwdy00OwiAQBtC7zFqS4Ufg8zLNUIaGDZjaxoXx7ja-_fvQc751X3qlB2Wp4kKCU47BZy4A7pa9uuitqNKN5t63PuToY1vO87-wri02gSlSiwloMKhcDZxoSClDAl-zj9exjHkFy0zfH5pUI3w.YfvMdQ.GcmMQuY3BN33JATAfFB3ZyeXO8U
RSA 加密代码:
String username="justin";
String encrypteduser=getEncryptedPassword(username);
System.out.println("encrypteduser! " + encrypteduser);
public String getEncryptedPassword(String plainTextPassword)
{
String result="";
try {
result= getEncryptedPasswd(plainTextPassword);
log.info("result: " + result);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
protected String getEncryptedPasswd(String plain) throws Exception {
try {
InputStream is = new ByteArrayInputStream(getCertificate().getBytes());
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
PublicKey pubKey = cert.getPublicKey();
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte cipherBytes[] = cipher.doFinal(plain.getBytes());
String encrypted = Base64.getEncoder().encodeToString(cipherBytes);
return encrypted;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
private String getCertificate() {
String certStr = "-----BEGIN CERTIFICATE-----\n"
+ "MIIGgDCCBWigAwIBAgIKMvrulAAAAARG5DANBgkqhkiG9w0BAQsFADBbMRMwEQYK"
+ "CZImiZPyLGQBGRYDbmV0MRkwFwYKCZIm"
+ "-----END CERTIFICATE-----";
return certStr;
}
我的目标是将 RSA 编码值压缩为缩短值。
我希望转换后(RSA
到 UTF-8
)会得到一些缩短的值。
注意:如果 UTF-8
转换没有帮助,则寻找对编码值的一些压缩。
在 java 8 中有什么方法可以做到这一点吗?
您的密文似乎已经采用 UTF-8 编码。它是 base-64 编码的; base-64 仅使用 US-ASCII 个字符,US-ASCII 编码是 UTF-8 编码的子集。
我相信你不是在要求你想要什么。你想要更短的密文吗?如果是这样,UTF-8 与此无关。
RSA 密文的长度等于 RSA 密钥的模数。 (这也对纯文本长度施加了上限。)根据安全要求选择密钥大小。现在 3072 位或 2048 位是典型的。对于这些密钥长度,通常支持的最短文本编码分别为 512 或 342 个字符。 (有一些不太常见的 binary-to-text 编码可以分别将其减少到 480 或 320 个字符,但它们会在 URL 和其他上下文中引起问题,因为它们使用更多的符号。)
如果您想要更短的密文,请使用不同的加密算法。对于 public 密钥加密,椭圆曲线算法使用较短的密钥提供相同级别的安全性(无论如何,据我们所知)。这意味着您的纯文本和密文将更短。或者,也许对称算法可能适用于您的方案。根据模式,这些可以输出与明文长度相同的密文(尽管这会泄露有关明文的信息并可能危及安全性)。
加密运算产生的字符串字节可以具有任何序列中的任何值。我不知道有任何 single-byte 字符编码将每个值映射到一个字符,也没有 multi-byte 字符编码将每个字节序列映射到一个字符。将这些事实放在一起,您将始终需要像 base-64 编码这样的东西来将您的密文转换为实际字符。因此,您的文本平均会长 33%。
为了与 7 位字符代码 US-ASCII 在很大程度上兼容,UTF-8 也仅使用低 7 位对单字节字符进行编码。这意味着使用 UTF-8 和 ASCII 中的单个字节存在相同的 95 个可打印字符。移动到两个或更高字节的 UTF-8 编码需要 更多 space,所以这根本没有用。
所以基本上您可以使用任何现有的 ASCII 文本编码。您已经在使用已经非常密集的 base 64。但是,您可以例如也使用 Z85 可以包含更多的二进制数据,缺点是它不是二的幂,所以编码/解码(或基本转换)会有些棘手和昂贵。此外,base 85 编码仅对 base 64 的 6 位中的每个字符编码大约 6.41 位,因此 return 是最小的(大约 6.82%)。
执行转换时应始终指明编码。但是,如前所述,UTF-8 完全兼容 Base 64 和 Z85 的 ASCII。所以我会指出编码 StandardCharsets.US_ASCII
,而不是 UTF_8
,因为其他人无疑会建议。
可以肯定的是:如果您能够处理字节,那么无编码总是比执行一些转换为效率较低的表示更好。
创建更小密文的唯一真正方法是查看混合加密。仅使用 RSA 加密或派生对称密钥并使用它来加密诸如密码之类的小字符串并不是真正可行的。 RSA 密文由(大部分)随机字节组成,因此至少平均而言不可能进一步压缩这些字节。
但是,您可以查看 ECIES,可能使用 压缩 临时 public 密钥。然后,您可以为 public 密钥(例如曲线类型 P256,强度为 128 位)使用 33 个字节,并为密码本身使用特定的最大密码大小,例如使用AES-CTR。您应该对密码使用静态大小的编码,否则可能会泄露密码大小。