have problems importing keys generated with php openssl to CryptoAPI
I successfully create key pair in php, crypt/decrypt a string with it – no problems
<?php $privateKey = openssl_pkey_new(array( 'private_key_bits' => 1024, 'private_key_type' => OPENSSL_KEYTYPE_RSA)); openssl_pkey_export($privateKey, $s); $info = openssl_pkey_get_details($privateKey); $public = openssl_pkey_get_public($info['key']); $private = openssl_pkey_get_private($s); $s = ''; $s1 = ''; openssl_public_encrypt('bla bla bla', $s, $public); openssl_private_decrypt($s, $s1, $private); echo('$s.'<br>'.$s1); ?>
Then I wrote a program in Delphi which should import private and public keys into CryptoAPI. I found some example private RSA key in internet and it imports with my code perfectly, but when I try to import a key generated with my php code it fails on CryptDecodeObjectEx function with “asn1 bad tag value met” error. Keys are quite similar except that php generates slightly longer key than I found in internet example, though they are both 1024 bits…
php generated key (does not work): priv_key: string = 'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAN/NfimL4/8Pmp7+' + 'j299I7yaT6SpF1jwrFlwlLLjDibehqjBOcao+CaLK8Se+hysqZGGwr2walUprGxG' + 'Z5hnfCQCOchbTs5CiXnBCIX1aPKaRMx/SX3b4moT+wnkLrGOnHnUM+2c+jqZUjdh' + '06hwlv1LCVcCtTW9NWU3Qi3G+r9bAgMBAAECgYBjjuSK0uJP+r8L764bKI4XPoYj' + 'd90dAaOJ/h0IHx2SiPdaZuqux0fszYhg5V/aFa0xQcOr4qjKzckYOZGoKJD+FtCq' + 'bNBEg1eZsKWYVJvTO8N2H0Lx4VSCiG7PjiqLGFfsmXZDXLPXhzsuCOUACmfcVoqh' + 'NlXOEAKtaTZI+uAakQJBAPB8sIQN7xTgCQcP2F8IbWR3VRAlnr4LWZQ5k96uxWjC' + 'wC6R8c7NnvUj+Fzs3XMXR8e3aTRme9OyHAWy7ReO+scCQQDuPUjBXXxuYGQq4ho5' + 'Pq4QEtHNKECDNDtKBaLvr9r7aXYOfMM/XiXqFqHAZqcrTRtMXD1sUhg4o+vIYkrg' + '5qLNAkEA6+Z0RGVitAh78ohxh+89V4LTV05/5A5AJe1BBvxLu1LmsAgLuf/rwK4z' + 'L/xN0lrw15EryvII34VkhZaZijV/+wJAfX52xrTSCOppmVVE7wafdgQT0/fyE6r9' + '2D4j2BJQTcL91x/NUaHsYuTNC6aHRH33dT/ZcyfDboKafxGX0+RpuQJBAMdPGszm' + 'JYhD9F8kz+Q9R04iuwupLxUU6Q60yVVZxRDBQ7OLxBQwrHa2WQ0TA8WC73TMNaph' + 'VN4ayHJHK8shjt0='; example key (works fine and it is shorter than php key): priv_key: string = 'MIICXAIBAAKBgQCf6YAJOSBYPve1jpYDzq+w++8YVoATI/YCi/RKZaQk+l2ZfoUQ' + 'g0qrYrfkzeoOa/qd5VLjTTvHEgwXnlDXMfo+vSgxosUxDOZXMTBqJGOViv5K2QBv' + 'k8A1wi4k8tuo/7OWya29HvcfavUk3YXaV2YFe8V6ssaZjNcVWmDdjqNkXwIDAQAB' + 'AoGALrd+ijNAOcebglT3ioE1XpUbUpbir7TPyAqvAZUUESF7er41jY9tnwgmBRgL' + 'Cs+M1dgLERCdKBkjozrDDzswifFQmq6PrmYrBkFFqCoLJwepSYdWnK1gbZ/d43rR' + '2sXzSGZngscx0CxO7KZ7xUkwENGd3+lKXV7J6/vgzJ4XnkECQQDTP6zWKT7YDckk' + 'We04hbhHyBuNOW068NgUUvoZdBewerR74MJx6nz28Tp+DeNvc0EveiQxsEnbV8u+' + 'NRkX5y0xAkEAwcnEAGBn5kJd6SpU0ALA9XEpUv7tHTAGQYgCRbfTT59hhOq6I22A' + 'ivjOCNG9c6E7EB2kcPVGuCpYUhy7XBIGjwJAK5lavKCqncDKoLwGn8HJdNcyCIWv' + 'q5iFoDw37gTt1ricg2yx9PzmabkDz3xiUmBBNeFJkw/FToXiQRGIakyGIQJAJIem' + 'PPPvYgZssYFbT4LVYO8d/Rk1FWVyKHQ9CWtnmADRXz7oK7l+m7PfEuaGsf9YpOcR' + 'koGJ/TluQLxNzUNQnQJBAImwr/yYFenIx3HQ6UX/fCt6qpGDv0VfOLyR64MNeegx' + 'o7DhNxHbFkIGzk4lKhMKcHKDrawZbdJtS9ie2geSwVQ=';
Code in Delphi which imports key:
var dwBufferLen, cbKeyBlob, i: longword; pbBuffer, pbKeyBlob: pointer; hProv: HCRYPTPROV; hKey: HCRYPTKEY; begin hProv := 0; hKey := 0; // convert key string to a binary if not(CryptStringToBinary(PWideChar(priv_key), 0, 1, nil, @dwBufferLen, nil, nil)) then exit; GetMem(pbBuffer, dwBufferLen); if not(CryptStringToBinary(PWideChar(priv_key), 0, 1, pbBuffer, @dwBufferLen, nil, nil)) then exit; // convert binary to a key blob if not(CryptDecodeObjectEx(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pbBuffer, dwBufferLen, 0, nil, nil, @cbKeyBlob)) then begin // first key generates error here ShowMessage(SysErrorMessage(GetLastError)); exit; end; GetMem(pbKeyBlob, cbKeyBlob); if not(CryptDecodeObjectEx(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pbBuffer, dwBufferLen, 0, nil, pbKeyBlob, @cbKeyBlob)) then exit; if not(CryptAcquireContext(@hProv, nil, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) then exit; if not(CryptImportKey(hProv, pbKeyBlob, cbKeyBlob, 0, 0, @hKey)) then exit; //... if hKey <> 0 then CryptDestroyKey(hKey); if hProv <> 0 then CryptReleaseContext(hProv, 0); end;
Advertisement
Answer
I found a solution.
PHP generates keys with extra fields in ASN.1 format compare to CryptoAPI keys.
1. I decoded base64 key into a binary file with help of this tool: base64 decoder
2. Then I just cut from this file first 26 bytes to the next header sequence starting from something like: “30 xx xx” and saved it.
3. And encoded this file back to base64 with: base64 encoder
Now I can import public and private keys into CryptoAPI without problems with next code:
// key types const PKCS_RSA_PRIVATE_KEY = LPCSTR(43); PKCS_RSA_PUBLIC_KEY = LPCSTR(19); function ImportKey(hProv: HCRYPTPROV; KeyType: pointer; key: string): hKey; var BuffSize, BlobSize: longword; buff, blob: pointer; begin result := 0; buff := nil; blob := nil; try if not(CryptStringToBinary(PWideChar(key), 0, 1, nil, @BuffSize, nil, nil)) then exit; GetMem(buff, BuffSize); if not(CryptStringToBinary(PWideChar(key), 0, 1, buff, @BuffSize, nil, nil)) then exit; if not(CryptDecodeObjectEx(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, KeyType, buff, BuffSize, 0, nil, nil, @BlobSize)) then exit; GetMem(blob, BlobSize); if not(CryptDecodeObjectEx(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, KeyType, buff, BuffSize, 0, nil, blob, @BlobSize)) then exit; if not(CryptImportKey(hProv, blob, BlobSize, 0, 0, @result)) then exit; finally if buff <> nil then FreeMem(buff); if blob <> nil then FreeMem(blob); end; end;