Skip to content

Private/Public Key Interoperability

If you do any work with private/public key cryptography, the addition of the Crypto library last year made it finally possible to create and verify digital signatures as well as encrypt and decrypt data. Using keys with other systems requires a little more work to convert them to and from the PEM format.

If you look at the Crypto docs you’ll see four methods:

  • BERDecodePrivateKey
  • BERDecodePublicKey
  • DEREncodePrivateKey
  • DEREncodePublicKey

Let’s start with converting from Xojo to PEM format.

You’ll need two methods, one for each of the private and public keys.

Function EncodePEMPrivateKey(privateKey as MemoryBlock, ByRef PEMPrivateKey as String) As Boolean
  const header = "-----BEGIN RSA PRIVATE KEY-----"
  const footer = "-----END RSA PRIVATE KEY-----"
  try
    Dim keystr As String = crypto.DEREncodePrivateKey(privateKey)
    keystr = EncodeBase64(keystr)
    PEMPrivateKey = header + EndOfLine + keystr + EndOfLine + footer
  catch ex as CryptoException
    Return False
  end try
  Return True
End Function
Function EncodePEMPublicKey(publicKey as MemoryBlock, ByRef PEMPublicKey as String) As Boolean
  const header = "-----BEGIN CERTIFICATE-----"
  const footer = "-----END CERTIFICATE-----"
  try
    Dim keystr As String = crypto.DEREncodePublicKey(publicKey)
    keystr = EncodeBase64(keystr)
    PEMPublicKey = header + EndOfLine + keystr + EndOfLine + footer
  catch ex as CryptoException
    Return False
  end try
  Return True
End Function

To convert back into a format that the Xojo Crypto methods can use, you’ll need two more methods:

Function DecodePEMPrivateKey(PEMPrivateKey as String, ByRef EncodedKey as MemoryBlock) As Boolean
  const header = "-----BEGIN RSA PRIVATE KEY-----"
  const footer = "-----END RSA PRIVATE KEY-----"
  // Make sure the header and footer exist
  if instr(PEMPrivateKey,header)=0 or instr(PEMPrivateKey,footer) = 0 then
    return False
  end if
  dim pos1 as integer = instr(PEMPrivateKey,header)+len(header)
  dim pos2 as integer = instr(PEMPrivateKey,footer)
  dim size as integer = pos2-pos1
  if size <= 0 then
    return False
  end if
  dim keystr as string = mid(PEMPrivateKey,pos1,size)
  keystr = DecodeBase64(keystr)
  try
    encodedkey = crypto.BERDecodePrivateKey(keystr)
  catch ex as CryptoException
    return False
  end try
  return true
End Function
Function DecodePEMPublicKey(PEMPublicKey as String, ByRef EncodedKey as MemoryBlock) As Boolean
  const header = "-----BEGIN CERTIFICATE-----"
  const footer = "-----END CERTIFICATE-----"
  // Make sure the header and footer exist
  if instr(PEMPublicKey,header)=0 or instr(PEMPublicKey,footer) = 0 then
    return False
  end if
  dim pos1 as integer = instr(PEMPublicKey,header)+len(header)
  dim pos2 as integer = instr(PEMPublicKey,footer)
  dim size as integer = pos2-pos1
  if size <= 0 then
    return False
  end if
  dim keystr as string = mid(PEMPublicKey,pos1,size)
  keystr = DecodeBase64(keystr)
  try
    encodedkey = crypto.BERDecodePublicKey(keystr)
  catch ex as CryptoException
    return False
  end try
  return true
End Function

To use these methods:

Dim priv,pub as String// Generate a key pair in Xojo
if Crypto.RSAGenerateKeyPair(1024,priv,pub) then
  // Now that we have the keys, convert them to PEM.
  // These versions could be used elsewhere, like in PHP or another language.
  dim PEMPublic, PEMPrivate as string
  PEMPublic = EncodePEMPublicKey(pub)
  PEMPrivate = EncodePEMPrivateKey(priv)

  // Now lets convert them back and use them  dim priv2,pub2 as MemoryBlock
  if DecodePEMPrivateKey(PEMPrivate,priv2) then
    if DecodePEMPublicKey(PEMPublic,pub2) then
      // When you get here, priv2 and pub2 contain
      // Now lets try encrypting/decrypting something
      dim s as string = "hello world"
      dim enc as string = crypto.RSAEncrypt(s,pub2)
      // Now lets decrypt that block
      dim dec as string = crypto.RSADecrypt(enc,priv2) 
    else
      // Public key failed to convert
    end if
  else
    // Private key failed to convert
  end if
end if

Have questions? Ask them here or on the Xojo Forum.