1

This is the first time I am doing this SSL pinning on Android.

When creating OkHttp, I am adding this code:

certificatePinner(
  CertificatePinner.Builder().add(
    "url of the server",
    "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
  ).build()
)

the second parameter expects this:

SHA-256 or SHA-1 hashes. Each pin is a hash of a certificate's Subject Public Key Info, base64-encoded and prefixed with either sha256/ or sha1/.

I was given a certificate in a txt file that starts with --BEGIN CERTIFICATE-- and ends with --END CERTIFICATE--.

I am struggling to extract the hash of Public Key Info and convert it to base64.

So far I have tried these methods:

Method 1: I put the certificate contents without BEGIN CERTIFICATE and END CERTIFICATE into some string variable. Tried to convert it into X509Certificate.

private fun certificateFromString(base64: String): X509Certificate? {
        val decoded = Base64.decode(base64, Base64.NO_WRAP)
        val inputStream = ByteArrayInputStream(decoded)
        return CertificateFactory.getInstance("X.509").generateCertificate(inputStream) as? X509Certificate
}

Then I pass this certificate here to get Sha256 hash of the public key. Also, pay attention to c.encoded and c.publicKey.encoded. I am not sure if the method works correctly.

private fun getFingerprint(c: X509Certificate?): String {
    var certificate = ""
    try {
        val md = MessageDigest.getInstance("SHA-256")
        var publicKey = ByteArray(0)
        if (c != null) {
            publicKey = md.digest(c.encoded) // I tried both
            publicKey = md.digest(c.publicKey.encoded) // I tried both
        }
        val hexString = StringBuilder()
        for (aPublicKeyByte in publicKey) {
            val appendString = Integer.toHexString(0xFF and aPublicKeyByte.toInt())
            if (appendString.length == 1) hexString.append("0")
            hexString.append(appendString)
        }
        certificate = hexString.toString()
    } catch (e1: NoSuchAlgorithmException) {
        e1.printStackTrace()
    } catch (e1: CertificateEncodingException) {
        e1.printStackTrace()
    }
    return certificate
}

then I am converting that string result to base64 like this:

private fun base64(openKey: String): String {
    return Base64.encodeToString(openKey.toByteArray(), Base64.NO_WRAP).toString()
}

then I add the resulting String into the CertificatePinner class as sha256/resultingStringInBase64.

Method 2: I changed the .txt into .pem in order to use openssl command line tools.

openssl rsa -in myCert.pem -pubout> myCert.pub

it returned writing RSA key

and when I open the generated myCert.pub, I see a text with ---BEGUN PUBLIC KEY--- and ---END PUBLIC KEY--- and a long list of letters between them.

Then I ran this to extract the sha256 hash:

openssl rsa -in myCert.pub -pubin -outform der | openssl dgst -sha256

this gave me a 64 character string 2c180286549...b1ba7.

Then I ran the command again but added base64 conversion.

openssl rsa -in myCert.pub -pubin -outform der | openssl dgst -sha256 | openssl enc -base64

The result is completely different than Method 1. Should it be the same? If so, could someone point me in the right direction? Or show how to properly get the SHA256 of Public Key.

amira
  • 416
  • 1
  • 7
  • 24
  • Certainly `c.publicKey.encoded` should return the public key in SubjectPublicKeyInfo (SPKI) format. Hash that with 256, then base64-encode the output of the hash. – President James K. Polk Aug 01 '22 at 00:50

1 Answers1

0

My method I just used recently and worked succesfully:

In your Terminal, where the folder containing public key file is located, write the command:

openssl x509 -in yourFile.pem -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

The result will be the your desired string (encoded in base64, which means that it'll have 44 characters, including an equal (=) symbol at the end), and must be placed in your Android code after sha256/....

Also, several methods could generate different hashes, so you can have multiple valid strings, meaning that both your generated hashes could be correct.

dazza5000
  • 7,075
  • 9
  • 44
  • 89
Robert Pal
  • 714
  • 1
  • 7
  • 15