A public/private keypair consists of a modulus, a private exponent, and a public exponent. The public key contains the modulus and the public exponent. The private key contains the modulus and the private exponent (http://en.wikipedia.org/wiki/RSA_(algorithm)).

PEM and DER are not really key formats, but rather a ways of
serializing certain data structures. Knowing that you have a PEM or
DER file is kind of like knowing that you have a CSV or a JSON
document. It tells you about the syntax, but it doesn't tell you what
the content *means*. The best way to find out what format your
key is stored in is to dump view the encoded structure a
DER-inspection tool.

A PEM file is a bas64-encoded DER file with a text header and footer.

More specifically, pem-data = "-----BEGIN PUBLIC KEY-----" + newline + base64( der-data ) + newline + "-----END PUBLIC KEY-----". For example:`-----BEGIN PUBLIC KEY----- MIIBCgKCAQEA8bx++TdhOI+4akK+MD6DfVf/jQWFyq3vN8YuRMB/LToZuLcnTclH 4QYua+rHi3XMuF1Hl0vVVvpU0Yjowj1E7GBJOV4qvcLOcyXfnXOO/+WMzOHeZTw9 A/LGfjiU+y6IcawwdbDPnDdKWc6B8KX/QALwa0JxWzzCNOgCdgmN4oE7tWGfS9O7 PMObAxsGdpgQ3y+5ugOnmQuXYKGl4Ii4xaW2Izg1SdYM23WA+f89JsSP9cEvlnpz 0yY6wkUv6tnp+nNFwGoNA8BYVtbKdXxRX2q49PZg7Dnl3F2i10DoAilaczJfgkAt oZTHG3YoXv/QRpeuHf/5RhupCJTm/DyQHQIDAQAB -----END PUBLIC KEY-----`

"DER" stands for 'Distinguished Encoding Rules', an ASN.1-based format for serializing structured information. Saying that a key is DER-encoded does not give a full picture, because you still need to know the encoded structure. I have seen both Public Key Info and RSA Public Key structures emitted by OpenSSL libraries. Both types of structures are described by X.509.

Since a public key is made of 2 integers, there is no such thing as
'raw public key data'. *Some* method of serialization must be
used to encode the numbers as a byte stream. Usually public keys are
stored as
DER-serializations of one of the
following X.509
structures:

A signature is an ASN.1 structure that includes a Public Key Info structure along with a bunch of other stuff. I do not wish to familiarize myself with the details of 'other stuff', but read on for details about the public key structures.

A Public Key Info is an ASN.1 sequence containing 2 elements: a
header giving information about the algorithm used (this header is
itself a sequence, with the name of the algorithm as the first element
("`rsaEncryption`

", for RSA keys, and I don't know what the
other element(s) are for; the ones I've looked at are empty), and a
DER-encoded RSA Public Key structure (read: not the RSA Public Key
sequence itself, but DER-serialized, so it will appear in the Public
Key Info sequence as a BitString) providing the actual key data.

i.e. ```
public-key-info = [ ["rsaEncryption", nil], der(
rsa-public-key ) ]
```

, "rsaEncryption" is an object id (tag=6) and
`der( rsa-public-key )`

indicates
an RSA Public Key structure serialized
using DER rules.

An RSA Public Key is an ASN.1 sequence containing 2 integers: the modulus (this should be a very large number) and the public exponent (a smaller one, usually 3, 17, or 65537). When encoded as an RSA Public Key in DER, a 2048-bit key usually takes up exactly 270 bytes.

i.e. `[ exponent, modulus ]`

, where exponent and modulus
are integers.

Java's `PublicKey#getEncoded()`

function returns a
DER-encoded structure that includes a header
("`rsaEncryption`

") and a BitString (tag=5) that includes
the 'raw key data.' To inspect the structure of a DER-encoded key, you
can use Ruby's `OpenSSL::ASN1`

module:

`asn1 = OpenSSL::ASN1.decode(File.read('public-key'))`

Generated with the help of some functions I wrote.

`function derToPem($der) { $pem = chunk_split(base64_encode($der), 64, "\n"); $pem = "-----BEGIN PUBLIC KEY-----\n".$pem."-----END PUBLIC KEY-----\n"; return $pem; } function pemToDer($pem) { if( !preg_match('#--+BEGIN PUBLIC KEY--+\n(.*)\n--+END PUBLIC KEY--+#s', $pem, $bif) ) { throw new Exception("Failed to parse PEM data: $pem"); } $base64 = $bif[1]; return base64_decode($base64); } $keyPair = openssl_pkey_new( array( 'digest_alg' => 'sha1', 'private_key_bits' => 2048, // For faster unit testing 'private_key_type' => OPENSSL_KEYTYPE_RSA ) ); $det = openssl_pkey_get_details($keyPair); /** PEM-formatted public key */ $pubKeyPem = $det['key']; $pubKeyDer = pemToDer($pubKeyPem);`

At this point `$pubKeyDer`

is the following DER-encoded structure:

Sequence[ Sequence[ ObjectID:"rsaEncryption", null ], BitString (270 bytes) ]

`package togos.cryptosandbox; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; public class RSAKeyGenerator { protected static KeyPair generateKeyPair() { try { KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); // On Harold... // 1024 bits = pretty much immediate // 2048 bits = takes a couple seconds // 4096 bits = takes many seconds kpg.initialize(2048); return kpg.generateKeyPair(); } catch( NoSuchAlgorithmException e ) { throw new RuntimeException(e); } } public static void writeFile( String filename, byte[] data ) throws IOException { File f = new File(filename); if( !f.getParentFile().exists() ) f.getParentFile().mkdirs(); FileOutputStream fos = new FileOutputStream(f); fos.write(data); fos.close(); } public static void main(String[] args) throws NoSuchAlgorithmException, IOException { KeyPair keyPair = generateKeyPair(); writeFile( "generated-keys/java/private-key", keyPair.getPrivate().getEncoded() ); writeFile( "generated-keys/java/public-key", keyPair.getPublic().getEncoded() ); } }`

The generated public key is the exact same structure as that generated by PHP:

`Sequence[ Sequence[ ObjectID:"rsaEncryption", null ], BitString (270 bytes) ]`

The private key is similar but has an integer and an OctetString instead of a BitString:

`Sequence[ Integer:0, Sequence[ ObjectID:"rsaEncryption", null ], OctetString (1192 bytes) ]`