我在ssh-rsa的公众是:
SSH-RSA AAAAB3NzaC1yc2EAAAADAQABAAABAQClAxT5S / WuX04OXBt9R59WcL45OmaU3M5U063lfyja7ovqaVR7 / 2kHtLF / LoCQCXSZMny8RTCGDjoXD7G / tGsyHFDHCI // Y1VDLE06AlDzrlu69DQY91 + 6gkhGjH3SF6us5hXlihrbSFLfAlSdkEs8gwSrspVQyuaOf + 39dnMddhEDYYg + z0ce82ta / n8xPBWCp60nDEDayNjOsRgzDJKSujNfngjQTL1x6qKJj8BW / P5lLJE1nbMm9BQD9G7glJk86qh1I / tJCnij6On0m6KcdzVz8cU3sBgNeB433kGjJtpxXXmJB6Vuu5IverhyfpiB4hP9WlKa / LSzW + ZIdvl /
我想将其转换为格式
以下的PKCS#1-----开始RSA公钥----- MIIBCgKCAQEAoL7K8ijUPfkkpdiIMIoHxzTn + npLzJGHr7QO09Mnz8Q1xFfv9Arr 3Eg2R7LdTMJ + v2Rk3EDRGJEwK8cWv5Hvh7KXIdRqtw2ouxY6pK9RXfvaQ0CF2nI9 Y7VxASdOvnI8byzlw9SvR1eDjpzIh8 / wtz3KcJK5aCRsAyH6ddvM4tPisQaKVBGN nCtPq94PspbpEYbNSQXTmnpO099P99oDXT + kpCaNrPvM5xWmUj0R7UwbmYYdNnVB UPFTKj + qVpp8TUTFUgk8noke7ABK6tncf8wmB8mPhgoKznZP5MaLZpB1f4gBeXst GNiLN4LwgRSM56eCEVqQHkVRuRrM9nODWQIDAQAB
----- END RSA PUBLIC KEY -----
总结:我想通过在java 7中使用上面的公钥验证文件,因为我面对ssh-rsa公钥的无效密钥格式错误,请告诉我需要做什么。
请在下面的代码段中找到:
byte[] decoded;
try {
decoded = Base64.getDecoder().decode(publickeyStr);
org.bouncycastle.asn1.pkcs.RSAPublicKey pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(decoded);
BigInteger modulus = pkcs1PublicKey.getModulus();
BigInteger publicExponent = pkcs1PublicKey.getPublicExponent();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory kf;
kf = KeyFactory.getInstance("RSA");
PublicKey generatedPublic = kf.generatePublic(keySpec);
System.out.printf("Modulus: %X%n", modulus);
System.out.printf("Public exponent: %d ... 17? Why?%n", publicExponent);
System.out.printf("See, Java class result: %s, is RSAPublicKey: %b%n", generatedPublic.getClass().getName(), generatedPublic instanceof RSAPublicKey);
} catch (Exception e) {
e.printStackTrace();
}
}
它给出了以下异常:
java.lang.IllegalArgumentException: Illegal base64 character 2d
at java.util.Base64$Decoder.decode0(Base64.java:714)
at java.util.Base64$Decoder.decode(Base64.java:526)
at java.util.Base64$Decoder.decode(Base64.java:549)
at SignVerify.convertPublicPKCS1StrToPKCS8PublicKeyObj(SignVerify.java:136)
at SignVerify.main(SignVerify.java:184)
答案 0 :(得分:1)
我在java中找不到任何可以做到的工具或解决方案。因此,我读取了RFC 4253的公钥格式描述和RFC 4251的mpint
描述。
RFC 4253的重要部分。第6.6节
The "ssh-rsa" key format has the following specific encoding:
string "ssh-rsa"
mpint e
mpint n
Here the 'e' and 'n' parameters form the signature key blob.
RFC 4251的重要部分
mpint
Represents multiple precision integers in two's complement format,
stored as a string, 8 bits per byte, MSB first. Negative numbers
have the value 1 as the most significant bit of the first byte of
the data partition. If the most significant bit would be set for
a positive number, the number MUST be preceded by a zero byte.
Unnecessary leading bytes with the value 0 or 255 MUST NOT be
included. The value zero MUST be stored as a string with zero
bytes of data.
By convention, a number that is used in modular computations in
Z_n SHOULD be represented in the range 0 <= x < n.
Examples:
value (hex) representation (hex)
----------- --------------------
0 00 00 00 00
9a378f9b2e332a7 00 00 00 08 09 a3 78 f9 b2 e3 32 a7
80 00 00 00 02 00 80
-1234 00 00 00 02 ed cc
-deadbeef 00 00 00 05 ff 21 52 41 11
知道这一切,编写代码将ssh-rsa密钥转换为java格式很容易。
private static int SIZEOF_INT = 4;
private static String key1 = "AAAAB3NzaC1yc2EAAAADAQABAAABAQClAxT5S/WuX04OXBt9R59WcL45OmaU3M5U063lfyja7ovqaVR7/2kHtLF/LoCQCXSZMny8RTCGDjoXD7G/tGsyHFDHCI//Y1VDLE06AlDzrlu69DQY91+6gkhGjH3SF6us5hXlihrbSFLfAlSdkEs8gwSrspVQyuaOf+39dnMddhEDYYg+z0ce82ta/n8xPBWCp60nDEDayNjOsRgzDJKSujNfngjQTL1x6qKJj8BW/P5lLJE1nbMm9BQD9G7glJk86qh1I/tJCnij6On0m6KcdzVz8cU3sBgNeB433kGjJtpxXXmJB6Vuu5IverhyfpiB4hP9WlKa/LSzW+ZIdvl/";
@Test
public void convertkey() throws Exception {
byte[] decoded = java.util.Base64.getDecoder().decode(key1);
try {
ByteBuffer byteBuffer = ByteBuffer.wrap(decoded);
AtomicInteger position = new AtomicInteger();
//first read algorithm, should be ssh-rsa
String algorithm = readString(byteBuffer, position);
System.out.println(algorithm);
assert "ssh-rsa".equals(algorithm);
// than read exponent
BigInteger publicExponent = readMpint(byteBuffer, position);
System.out.println("publicExponent = " + publicExponent);
// than read modulus
BigInteger modulus = readMpint(byteBuffer, position);
System.out.println("modulus = " + modulus);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey publicKey = kf.generatePublic(keySpec);
System.out.printf("Modulus: %X%n", modulus);
System.out.printf("Public exponent: %d ... 17? Why?%n", publicExponent);
System.out.printf("See, Java class result: %s, is RSAPublicKey: %b%n", publicKey.getClass().getName(), publicKey instanceof RSAPublicKey);
byte[] pubBytes = publicKey.getEncoded();
SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo.getInstance(pubBytes);
ASN1Primitive primitive = spkInfo.parsePublicKey();
writePEM("pubPkcs1.pem", "RSA PUBLIC KEY", primitive.getEncoded() );
} catch (Exception e) {
e.printStackTrace();
}
}
private BigInteger readMpint(ByteBuffer buffer, AtomicInteger pos){
byte[] bytes = readBytes(buffer, pos);
if(bytes.length == 0){
return BigInteger.ZERO;
}
return new BigInteger(bytes);
}
private String readString(ByteBuffer buffer, AtomicInteger pos){
byte[] bytes = readBytes(buffer, pos);
if(bytes.length == 0){
return "";
}
return new String(bytes, StandardCharsets.US_ASCII);
}
private byte[] readBytes(ByteBuffer buffer, AtomicInteger pos){
int len = buffer.getInt(pos.get());
byte buff[] = new byte[len];
for(int i = 0; i < len; i++) {
buff[i] = buffer.get(i + pos.get() + SIZEOF_INT);
}
pos.set(pos.get() + SIZEOF_INT + len);
return buff;
}
private void writePEM(String fileName, String header, byte[] content) throws IOException{
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
PemObject pemObject = new PemObject(header, content);
PemWriter pemWriter = new PemWriter(fw);
pemWriter.writeObject(pemObject);
pemWriter.close();
}
输出
ssh-rsa
publicExponent = 65537
modulus = 20830840075214895520187085209140532093913000825284169131015003256319574044057453999265862514662442478787476545768050679936827456316397871442660366713280574836948529205417590573371022714192162142283026905055750951413644811120376414428742776306570652231542058994893537065648692533801879404176161589597321580633083481631733302249100913607754671673449460161582195402470090670605789220193388312197339358656479303453367386441996440265509774568364904443092245613429875362588897307051303623648237031289817493491475305022256278911859470009225208699382584578527080735302630318546541433464398236590978005758010444925861059033471
Modulus: A50314F94BF5AE5F4E0E5C1B7D479F5670BE393A6694DCCE54D3ADE57F28DAEE8BEA69547BFF6907B4B17F2E8090097499327CBC4530860E3A170FB1BFB46B321C50C7088FFF6355432C4D3A0250F3AE5BBAF43418F75FBA8248468C7DD217ABACE615E58A1ADB4852DF02549D904B3C8304ABB29550CAE68E7FEDFD76731D76110361883ECF471EF36B5AFE7F313C1582A7AD270C40DAC8D8CEB118330C9292BA335F9E08D04CBD71EAA2898FC056FCFE652C91359DB326F41403F46EE094993CEAA87523FB490A78A3E8E9F49BA29C773573F1C537B0180D781E37DE41A326DA715D798907A56EBB922F7AB8727E9881E213FD5A529AFCB4B35BE64876F97F
Public exponent: 65537 ... 17? Why?
See, Java class result: sun.security.rsa.RSAPublicKeyImpl, is RSAPublicKey: true
第二部分 - 将java对象保存为pkcs1公钥。
如果你编写pubkeys.getEncoded()你得到了pkcs8公钥,RSA公钥就不同了。 RFC 3447附录A.1.1中描述的格式
An RSA public key should be represented with the ASN.1 type
RSAPublicKey:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
The fields of type RSAPublicKey have the following meanings:
* modulus is the RSA modulus n.
* publicExponent is the RSA public exponent e.
This question特别是Ian Boyd的回答提供了许多细节。
Bouncy castle已经有了SubjectPublicKeyInfo
级来处理这种情况。
转换为pkcs8和pkcs1格式的代码:
byte[] pubBytes = publicKey.getEncoded();
//writePEM("pubPkcs8.pem", "PUBLIC KEY", pubBytes ); // if you need pkcs8
SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo.getInstance(pubBytes);
ASN1Primitive primitive = spkInfo.parsePublicKey();
writePEM("pubPkcs1.pem", "RSA PUBLIC KEY", primitive.getEncoded() );
pubPkcs1.pem的内容
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEApQMU+Uv1rl9ODlwbfUefVnC+OTpmlNzOVNOt5X8o2u6L6mlUe/9p
B7Sxfy6AkAl0mTJ8vEUwhg46Fw+xv7RrMhxQxwiP/2NVQyxNOgJQ865buvQ0GPdf
uoJIRox90herrOYV5Yoa20hS3wJUnZBLPIMEq7KVUMrmjn/t/XZzHXYRA2GIPs9H
HvNrWv5/MTwVgqetJwxA2sjYzrEYMwySkrozX54I0Ey9ceqiiY/AVvz+ZSyRNZ2z
JvQUA/Ru4JSZPOqodSP7SQp4o+jp9JuinHc1c/HFN7AYDXgeN95BoybacV15iQel
bruSL3q4cn6YgeIT/VpSmvy0s1vmSHb5fwIDAQAB
-----END RSA PUBLIC KEY-----
使用openssl检查结果
$ openssl asn1parse -in pubPkcs1.pem
0:d=0 hl=4 l= 266 cons: SEQUENCE
4:d=1 hl=4 l= 257 prim: INTEGER :A50314F94BF5AE5F4E0E5C1B7D479F5670BE393A6694DCCE54D3ADE57F28DAEE8BEA69547BFF6907B4B17F2E8090097499327CBC4530860E3A170FB1BFB46B321C50C7088FFF6355432C4D3A0250F3AE5BBAF43418F75FBA8248468C7DD217ABACE615E58A1ADB4852DF02549D904B3C8304ABB29550CAE68E7FEDFD76731D76110361883ECF471EF36B5AFE7F313C1582A7AD270C40DAC8D8CEB118330C9292BA335F9E08D04CBD71EAA2898FC056FCFE652C91359DB326F41403F46EE094993CEAA87523FB490A78A3E8E9F49BA29C773573F1C537B0180D781E37DE41A326DA715D798907A56EBB922F7AB8727E9881E213FD5A529AFCB4B35BE64876F97F
265:d=1 hl=2 l= 3 prim: INTEGER :010001