0

My Public in ssh-rsa is:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQClAxT5S/WuX04OXBt9R59WcL45OmaU3M5U063lfyja7ovqaVR7/2kHtLF/LoCQCXSZMny8RTCGDjoXD7G/tGsyHFDHCI//Y1VDLE06AlDzrlu69DQY91+6gkhGjH3SF6us5hXlihrbSFLfAlSdkEs8gwSrspVQyuaOf+39dnMddhEDYYg+z0ce82ta/n8xPBWCp60nDEDayNjOsRgzDJKSujNfngjQTL1x6qKJj8BW/P5lLJE1nbMm9BQD9G7glJk86qh1I/tJCnij6On0m6KcdzVz8cU3sBgNeB433kGjJtpxXXmJB6Vuu5IverhyfpiB4hP9WlKa/LSzW+ZIdvl/

I wanted to convert it to PKCS#1 below format

-----BEGIN RSA PUBLIC KEY----- MIIBCgKCAQEAoL7K8ijUPfkkpdiIMIoHxzTn+npLzJGHr7QO09Mnz8Q1xFfv9Arr 3Eg2R7LdTMJ+v2Rk3EDRGJEwK8cWv5Hvh7KXIdRqtw2ouxY6pK9RXfvaQ0CF2nI9 Y7VxASdOvnI8byzlw9SvR1eDjpzIh8/wtz3KcJK5aCRsAyH6ddvM4tPisQaKVBGN nCtPq94PspbpEYbNSQXTmnpO099P99oDXT+kpCaNrPvM5xWmUj0R7UwbmYYdNnVB UPFTKj+qVpp8TUTFUgk8noke7ABK6tncf8wmB8mPhgoKznZP5MaLZpB1f4gBeXst GNiLN4LwgRSM56eCEVqQHkVRuRrM9nODWQIDAQAB

-----END RSA PUBLIC KEY-----

Summary : I want to verify file by using above public key in java 7 as i am facing the invalid key format error for ssh-rsa public key kindly let me know what need to be done.

please find below snippet:

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();
        }
    }

it is giving below exception:

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)
Shirin Shaikh
  • 11
  • 1
  • 2
  • 2
    _provide the code snippet for the same.ASAP_ This sentence is best way to get more downvotes and close votes for your question. Please read Help Center to know how to ask questions. – Pradeep Simha May 15 '17 at 11:23
  • Welcome to Stack Overflow! Please [edit] your question to show [the code you have so far](http://whathaveyoutried.com). You should include at least an outline (but preferably a [mcve]) of the code that you are having problems with, then we can try to help with the specific problem. You should also read [ask]. – Toby Speight May 15 '17 at 11:26
  • Besides that impolite request to give answers asap - please understand that this is not a free coding service where you drop your requirements and other people do the work for you. In other words: what have you tried to solve your problem yourself? What research have you done? – GhostCat May 15 '17 at 11:35
  • Have you seen https://unix.stackexchange.com/questions/333401/convert-openssh-public-key-to-a-pkcs1-in-hex-format-with-spaces-and-columns for example? Just putting your question title into google gives a **ton** of links. Try reading that stuff first! – GhostCat May 15 '17 at 11:38
  • @GhostCat i had tried many links including that one but i wanted to do in java not using any linux commands ...after N numbers of trials i have put this here..so any kind of help would be appreciated. – Shirin Shaikh May 15 '17 at 12:13
  • Are you sure that your input is encoded in base64? The string should end with "=" in that case?! – GhostCat May 15 '17 at 12:15
  • the input public key has been generated by using putty keygen tool .. – Shirin Shaikh May 15 '17 at 12:18
  • @GhostCat = symbol uses for padding, so base64 string can contains one or two = in the end, but it is not mandatory, it depends of input data. – user1516873 May 15 '17 at 12:36
  • @user1516873 Obviously the library contains about non-base 64 encoded values. So chances are that something about the input is problematic. – GhostCat May 15 '17 at 12:38
  • @GhostCat Stacktrace is clearly say that base64 data is corrupted, but i think that is irrelevant. If you check sample ssh-rsa key, it is valid and perfectly decoded from base64. I am not sure it is possible to do asked conversion in general in java (without openssl), but it is interesting question. – user1516873 May 15 '17 at 12:44
  • @user1516873 I am pretty sure that this error matters to the OP; or why else are we looking at the error message in the question text? ;-) – GhostCat May 15 '17 at 12:46
  • Once again my problem is : i want to verify file using the IP public key but i am not able to do it as the key format is different from the expected one..so kindly let me know any method to follow. – Shirin Shaikh May 15 '17 at 13:01

1 Answers1

3

I do not find any tool or solutions in java that can do it. So, I read RFC 4253 for public key format description and RFC 4251 for mpint description. Important parts from RFC 4253. section 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.

And important part from 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

Know all this, write code to convert ssh-rsa key to java format is easy.

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();
}

output

ssh-rsa
publicExponent = 65537
modulus = 20830840075214895520187085209140532093913000825284169131015003256319574044057453999265862514662442478787476545768050679936827456316397871442660366713280574836948529205417590573371022714192162142283026905055750951413644811120376414428742776306570652231542058994893537065648692533801879404176161589597321580633083481631733302249100913607754671673449460161582195402470090670605789220193388312197339358656479303453367386441996440265509774568364904443092245613429875362588897307051303623648237031289817493491475305022256278911859470009225208699382584578527080735302630318546541433464398236590978005758010444925861059033471
Modulus: A50314F94BF5AE5F4E0E5C1B7D479F5670BE393A6694DCCE54D3ADE57F28DAEE8BEA69547BFF6907B4B17F2E8090097499327CBC4530860E3A170FB1BFB46B321C50C7088FFF6355432C4D3A0250F3AE5BBAF43418F75FBA8248468C7DD217ABACE615E58A1ADB4852DF02549D904B3C8304ABB29550CAE68E7FEDFD76731D76110361883ECF471EF36B5AFE7F313C1582A7AD270C40DAC8D8CEB118330C9292BA335F9E08D04CBD71EAA2898FC056FCFE652C91359DB326F41403F46EE094993CEAA87523FB490A78A3E8E9F49BA29C773573F1C537B0180D781E37DE41A326DA715D798907A56EBB922F7AB8727E9881E213FD5A529AFCB4B35BE64876F97F
Public exponent: 65537 ... 17? Why?
See, Java class result: sun.security.rsa.RSAPublicKeyImpl, is RSAPublicKey: true

Second part - save java object as pkcs1 public key.

If you write pubkeys.getEncoded() you got pkcs8 public key, RSA public key is different. Format described in RFC 3447 appendix 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 ans especially Ian Boyd's answer gives many details.

Bouncy castle already has class SubjectPublicKeyInfo to handle this situation.

Code to convert to pkcs8 and pkcs1 format:

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() );

content of 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-----

checking results with 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
Community
  • 1
  • 1
user1516873
  • 5,060
  • 2
  • 37
  • 56