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.