I create a file using openssl from the commandline. Let's say:
echo 'foobar' | openssl enc -aes-128-cbc -e -pass pass:testing >
sample
I can decrypt this doing
cat sample | openssl enc -aes-128-cbc -d -pass pass:testing
That works fine.
Now I want to decrypt that file using the openssl c/c++ API but I can't get this quite right. I am trying to decrypt like so
#include <fstream>
#include <memory>
#include <string>
#include <openssl/err.h>
#include <openssl/evp.h>
using EVP_CIPHER_CTX_free_ptr = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>;
int main(int argc, char* argv[])
{
ERR_load_crypto_strings();
EVP_add_cipher(EVP_aes_128_cbc());
std::string l_key{"testing"};
std::string l_ctext{};
std::ifstream l_file("sample", std::ios::binary | std::ios::in | std::ios::ate);
if(l_file.is_open())
{
std::streampos l_size = l_file.tellg();
char * lp_buffer = new char[l_size];
l_file.seekg(0, std::ios::beg);
l_file.read(lp_buffer, l_size);
l_ctext.append(lp_buffer, l_size);
delete lp_buffer;
l_file.close();
}
std::string l_rtext;
EVP_CIPHER_CTX_free_ptr ctx(EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_cbc(), NULL,
(const unsigned char*)l_key.c_str(), NULL));
ERR_print_errors_fp(stdout);
int l_len;
if(1 != EVP_DecryptUpdate(ctx.get(), (unsigned char*)&l_rtext[0], &l_len,
(const unsigned char*)l_ctext.data(),
l_ctext.size()))
ERR_print_errors_fp(stdout);
if(1 != EVP_DecryptFinal_ex(ctx.get(), (unsigned char*)&l_rtext[0] + l_len,
&l_len))
ERR_print_errors_fp(stdout);
ERR_free_strings();
exit(0);
}
However that last call to EVP_DecryptFinal_ex fails with
140559955420968:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:596:
Most of this code is based on the examples that come with the openssl API. What am I doing wrong? I set the IV to NULL in EVP_DecryptInit_ex because as far as I found out, this is acceptable as long as I don't use the key multiple times.
All this on a Fedora machine with GCC
I kind of figured out what I did wrong.
The commandline 'openssl enc' command uses a default salt, my code above didn't look for that. So (rather than try to work with the '-nosalt' option) I remove the first 16 bytes from the encrypted string and use the last 8 of that as the salt.
I was feeding the password to the EVP methods as a 'key'. It seems 'openssl enc' doesn't do this so one needs to use the salt and the password to create a key and IV (rather than using NULL which is what I did).
There was an error in the above code in that l_rtext needs a resize() to reflect the fact that characters were added to it.
Related
I am trying to convert a hex string to pem format using openssl, I can do it using the openssl command but would like to do in c++ rather then rely on breaking out to the console
Example Hex String:
308204A33082038BA00302010202100AED96BA818D647A58A925ED9DB78884300D06092A864886F70D01010B05003081B9310B30090603550406130247423110300E06035504080C07456E676C616E643120301E060355040A0C1746616C636F6E20456C656374726963204C696D6974656431143012060355040B0C0B46616C636F6E436C6F7564312E302C06035504030C2546616C636F6E20456C65637472696320435020496E7465726D6564696174652043412076323130302E06092A864886F70D01090116216365727469666963617465734066616C636F6E656C6563747269632E636F2E756B301E170D3233303230373136323335325A170D3238303230363136323335325A3081A2310B300906035504060C024742310F300D06035504080C064C6F6E646F6E310F300D06035504070C064C6F6E646F6E31163014060355040A0C0D536978205761747473204C746431143012060355040B0C0B436861726765506F696E743115301306035504030C0C44384230335743525350514B312C302A06092A864886F70D010901161D63657274696669636174657340706C756773747265616D2E636F2E756B30820122300D06092A864886F70D01010105000382010F003082010A0282010100E2FBE3385753EB2A7EFD72AFE4B1344619F1FF5A31FEEE7118461E24795E540C498E384B81A2B56490CB1A203B12FCEC2BBFBC89C73801EA3CED5377A71E4E43B5B1AF2AD0AD6DCF126109B611A98379FE0E4CAA1DFE4230E44CF1100EFAC470FA4531D61B3F2CBC3AFA088E40F418B8CA918A44467E0F8C10D6C7BBD6B469B228CDE89E989AFA53E0D38CB86B23881C763744504D4BF1D0045847BCB24182B658319BC4B77C4C61D9025384BA3162C3C05A2F1EDF26B1807D7880A121729D5A2268A4264B3359789EE7E619CD33473CC0FB3693D76803529EA2BC383896A5D308797A375219FB10D935CD01F94C0CB4E37E72F86B9CE85005508CECDA801A7D0203010001A381BB3081B830090603551D1304023000301106096086480186F8420101040403020780303306096086480186F842010D042616244F70656E53534C2047656E65726174656420436C69656E74204365727469666963617465301D0603551D0E04160414D7A4917FCFA7906645D0ACBF316AB9677ECE958D301F0603551D23041830168014141E12E19554AF8E5D660604DDAC378781981197300E0603551D0F0101FF0404030205E030130603551D25040C300A06082B06010505070302300D06092A864886F70D01010B050003820101003927F4A0B5A5AED55FBA6243CCF9A7A644AFBE7A143375620A8672B943F85B8F603AF9FD59024FDA60C48E5C5A4BA778037D0A6956E9DB81EA1517FC9BADB86ECAF28B8B8B15B856BC5FFE648C61186CE79F8D9C68BEED02650CC1CAF550BF844A7CD38161D3518196BC5A28DC06B0DEDC3C9DDF61F20AF73EE0FC3ADC2AA537E36D46097B9B930A8C7C1366D3F6F4C42280D6AE32CD50F9E88850A110721CB1BB3FC3EACA2F5F8A5C079E2BDAC19A4CB796B722F5F88B36F7A6BAC3DE2AB33CDCFE3877BCC3B84935FEC029CA4D26B4583DB3AC7F4FD48D06F74308DA5A931C2FE165A8352FC6E89691761FC39242ED1D506C53FF9826FD28F3138E6DDAB9FA
I am writing the above to a file and then converting using xxd and openssl to pem formated cert
cat example.txt | xxd -r -p | openssl x509 -inform der -out example.cert which produces something like. Truncated to reduce size of the post.
-----BEGIN CERTIFICATE-----
MIIEozCCA4ugAwIBAgIQCu2WuoGNZHpYqSXtnbeIhDANBgkqhkiG9w0BAQsFADCB
...
B54r2sGaTLeWtyL1+Is296a6w94qszzc/jh3vMO4STX+wCnKTSa0WD2zrH9P1I0G
90MI2lqTHC/hZag1L8bolpF2H8OSQu0dUGxT/5gm/SjzE45t2rn6
-----END CERTIFICATE-----
How can I do this in c++ using openssl?
I have also tried from Convert a plain public key to PEM
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/pem.h>
#ifdef _WIN32
#include <openssl/applink.c>
#endif
void err (const char *label){ // for test; improve for real code
fprintf (stderr, "Error in %s:\n", label);
ERR_print_errors_fp (stderr);
exit (1);
}
int main (void) //(int argc, char**argv)
{
ERR_load_crypto_strings(); /* or SSL_load_error_strings */
//OPENSSL_add_all_algorithms_noconf(); /* for PKCS#8 */
// test data -- replace for real use
char hex [] = "308204A33082038BA00302010202100AED96BA818D647A58A925ED9DB78884300D06092A864886F70D01010B05003081B9310B30090603550406130247423110300E06035504080C07456E676C616E643120301E060355040A0C1746616C636F6E20456C656374726963204C696D6974656431143012060355040B0C0B46616C636F6E436C6F7564312E302C06035504030C2546616C636F6E20456C65637472696320435020496E7465726D6564696174652043412076323130302E06092A864886F70D01090116216365727469666963617465734066616C636F6E656C6563747269632E636F2E756B301E170D3233303230373136323335325A170D3238303230363136323335325A3081A2310B300906035504060C024742310F300D06035504080C064C6F6E646F6E310F300D06035504070C064C6F6E646F6E31163014060355040A0C0D536978205761747473204C746431143012060355040B0C0B436861726765506F696E743115301306035504030C0C44384230335743525350514B312C302A06092A864886F70D010901161D63657274696669636174657340706C756773747265616D2E636F2E756B30820122300D06092A864886F70D01010105000382010F003082010A0282010100E2FBE3385753EB2A7EFD72AFE4B1344619F1FF5A31FEEE7118461E24795E540C498E384B81A2B56490CB1A203B12FCEC2BBFBC89C73801EA3CED5377A71E4E43B5B1AF2AD0AD6DCF126109B611A98379FE0E4CAA1DFE4230E44CF1100EFAC470FA4531D61B3F2CBC3AFA088E40F418B8CA918A44467E0F8C10D6C7BBD6B469B228CDE89E989AFA53E0D38CB86B23881C763744504D4BF1D0045847BCB24182B658319BC4B77C4C61D9025384BA3162C3C05A2F1EDF26B1807D7880A121729D5A2268A4264B3359789EE7E619CD33473CC0FB3693D76803529EA2BC383896A5D308797A375219FB10D935CD01F94C0CB4E37E72F86B9CE85005508CECDA801A7D0203010001A381BB3081B830090603551D1304023000301106096086480186F8420101040403020780303306096086480186F842010D042616244F70656E53534C2047656E65726174656420436C69656E74204365727469666963617465301D0603551D0E04160414D7A4917FCFA7906645D0ACBF316AB9677ECE958D301F0603551D23041830168014141E12E19554AF8E5D660604DDAC378781981197300E0603551D0F0101FF0404030205E030130603551D25040C300A06082B06010505070302300D06092A864886F70D01010B050003820101003927F4A0B5A5AED55FBA6243CCF9A7A644AFBE7A143375620A8672B943F85B8F603AF9FD59024FDA60C48E5C5A4BA778037D0A6956E9DB81EA1517FC9BADB86ECAF28B8B8B15B856BC5FFE648C61186CE79F8D9C68BEED02650CC1CAF550BF844A7CD38161D3518196BC5A28DC06B0DEDC3C9DDF61F20AF73EE0FC3ADC2AA537E36D46097B9B930A8C7C1366D3F6F4C42280D6AE32CD50F9E88850A110721CB1BB3FC3EACA2F5F8A5C079E2BDAC19A4CB796B722F5F88B36F7A6BAC3DE2AB33CDCFE3877BCC3B84935FEC029CA4D26B4583DB3AC7F4FD48D06F74308DA5A931C2FE165A8352FC6E89691761FC39242ED1D506C53FF9826FD28F3138E6DDAB9FA";
unsigned char raw [65]; for( int i = 0; i < 65; i++ ){ sscanf(hex+2*i, "%2hhx", raw+i); }
EC_KEY *eck = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); /* or OBJ_txt2nid("prime256v1") */
if( !eck ) err("ECCnewbyname");
EC_KEY_set_asn1_flag(eck, OPENSSL_EC_NAMED_CURVE); /* needed below 1.1.0 */
const unsigned char *ptr = raw;
if( !o2i_ECPublicKey (&eck, &ptr, sizeof(raw)) ) err("o2iECPublic=point");
EVP_PKEY * pkey = EVP_PKEY_new();
if( !EVP_PKEY_assign_EC_KEY(pkey, eck) ) err("PKEYassign");
BIO *bio = BIO_new(BIO_s_mem());
if( !PEM_write_bio_PUBKEY (bio, pkey) ) err("PEMwrite");
char *pem = NULL; long len = BIO_get_mem_data (bio, &pem);
fwrite (pem, 1, len, stdout); // for test; for real use as needed
return 0;
}
But I get
Error in o2iECPublic=point:
40B790FB647F0000:error:08000066:elliptic curve routines:ossl_ec_GFp_simple_oct2point:invalid encoding:../crypto/ec/ecp_oct.c:295:
40B790FB647F0000:error:08080010:elliptic curve routines:o2i_ECPublicKey:EC lib:../crypto/ec/ec_asn1.c:1142:
What am I doing wrong?
I'm planning on using the crypto++ library for a web application and wasm seemed perfect for it.
My cpp code:
#include <string>
using std::string;
#include "cryptopp/cryptlib.h"
#include "cryptopp/rsa.h"
#include "cryptopp/files.h"
#include "cryptopp/osrng.h"
using CryptoPP::RSA;
using CryptoPP::InvertibleRSAFunction;
using CryptoPP::RSAES_OAEP_SHA_Encryptor;
using CryptoPP::RSAES_OAEP_SHA_Decryptor;
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::PK_EncryptorFilter;
using CryptoPP::PK_DecryptorFilter;
using CryptoPP::FileSink;
using CryptoPP::FileSource;
using CryptoPP::AutoSeededRandomPool;
using CryptoPP::DecodingResult;
using CryptoPP::SHA1;
using namespace CryptoPP;
extern "C" {
char* generateKeys() {
AutoSeededRandomPool rng;
InvertibleRSAFunction parameters;
parameters.GenerateRandomWithKeySize(rng, 1024);
RSA::PrivateKey privateKey(parameters);
RSA::PublicKey publicKey(parameters);
string pubKey;
publicKey.Save(StringSink(pubKey).Ref());
privateKey.Save(FileSink("privkey.der", true).Ref());
int n = pubKey.length();
char* char_array = new char[n + 1];
strcpy(char_array, pubKey.c_str());
return char_array;
}
}
extern "C" {
char* encrypt(string pubKey, string plain) {
AutoSeededRandomPool rng;
string cipher;
RSA::PublicKey publicKey;
publicKey.Load(StringSource(pubKey, true, NULL).Ref());
RSAES_OAEP_SHA_Encryptor e(publicKey);
StringSource(plain, true,
new PK_EncryptorFilter(rng, e,
new StringSink(cipher)
) // PK_EncryptorFilter
); // StringSource
int n = cipher.length();
char* char_array = new char[n + 1];
strcpy(char_array, cipher.c_str());
return char_array;
}
}
extern "C" {
char* decrypt(const char* filename, string cipher) {
AutoSeededRandomPool rng;
RSA::PrivateKey privateKey;
string recovered;
privateKey.Load(FileSource(filename, true).Ref());
RSAES_OAEP_SHA_Decryptor d(privateKey);
StringSource(cipher, true,
new PK_DecryptorFilter(rng, d,
new StringSink(recovered)
) // PK_EncryptorFilter
); // StringSource
int n = recovered.length();
char* char_array = new char[n + 1];
strcpy(char_array, recovered.c_str());
return char_array;
}
}
I referred emscripten documentation for using libraries in emscripten
I created cryptlib.a using the cryptlib.cpp file and compiled it using emcc like so
emcc -c -o cryptlib.o cryptlib.cpp
ar rcs cryptlib.a cryptlib.o
Finally I also created Source.o like so
emcc -c -o Source.o Source.cpp
I figured out that this would the command to get an html and js file
emcc Source.o cryptlib.a -o source.html -sEXPORTED_FUNCTIONS=_generateKeys -sEXPORTED_RUNTIME_METHODS=ccall,cwrap
I get wasm-ld errors like so
Error screenshots
What am I doing wrong? I also want to expose other functions of my source code but I was testing with just one of the functions.
Looks like you try to use the native version of crypto++, and this will only work if you build the webassembly version of the library.
EDIT: sorry... you were already trying that...
I saw your question here as I was doing it myself.
this is what I just published, which might help:
=> wasm online demo:
===> https://guillaumebouchetepitech.github.io/wasm-cryptopp-demo/dist/index.html
=> source code:
===> https://github.com/GuillaumeBouchetEpitech/wasm-cryptopp-demo
PS: I've added the code to set/get string values to/from the js/wasm code as well, it's not overly well done but it feels like you could also get started on that side as well thanks to it.
let me know.
the code below implements a working example for string encryption using RSA and cryptopp. It is an adaption of the examples available from the crypto++ wiki. The problem is that an exception is thrown if the string is large than 342.
terminate called after throwing an instance of 'CryptoPP::InvalidArgument'
what(): RSA/OAEP-MGF1(SHA-1): message length of 1000 exceeds the maximum of 342 for this public key
A similar situation arises if the source/sink is a file.
There are at least 3 options to deal with that problem
make the key larger
slice the string manually before calling the encryption function
configure/call cryptopp in a way that it can handle the long string.
The latter option would be the most sensible, and I am sure it exists, but I have failed so far to figure out the correct setup.
Any ideas are highly appreciated.
#include <string>
#include <cryptlib.h>
#include <rsa.h>
#include "osrng.h"
#include <iostream>
#include <queue.h>
#include <files.h>
#include "base64.h"
using namespace std;
using namespace CryptoPP;
void b(string plain){
CryptoPP::AutoSeededRandomPool rng;
CryptoPP::InvertibleRSAFunction params;
params.GenerateRandomWithKeySize(rng, 3072);
CryptoPP::RSA::PrivateKey privateKey(params);
CryptoPP::RSA::PublicKey publicKey(params);
std::string cipher, recovered;
CryptoPP::RSAES_OAEP_SHA_Encryptor e(publicKey);
CryptoPP::StringSink sink(cipher);
CryptoPP::PK_EncryptorFilter filter(rng,e);
filter.Attach(new Redirector(sink));
CryptoPP::StringSource ss1(plain, false);
ss1.Attach(new Redirector(filter));
ss1.PumpAll();
CryptoPP::RSAES_OAEP_SHA_Decryptor d(privateKey);
CryptoPP::StringSource ss2(cipher, true,
new CryptoPP::PK_DecryptorFilter(rng, d,
new CryptoPP::StringSink(recovered)
) // PK_DecryptorFilter
); // StringSource
std::cout <<recovered << std::endl;
}
int main(){
string plain;
for(int i=0;i<1000;++i){
plain.push_back('A');
}
b(plain);
}
The ONVIF authentication spec section 6.1.1.3 has what looks like a straight forward description of how to generate a digest. However, when using Crypto++ for Base64 and SHA1 operations, I cannot generate the same hash as the specification. I must be doing something wrong but cannot see what.
std::string nonce = "LKqI6G/AikKCQrN0zqZFlg==";
std::string dt = "2010-09-16T07:50:45Z";
std::string pwd = "userpassword";
{
// result should be tuOSpGlFlIXsozq4HFNeeGeFLEI=
// as per spec. This approach is also used here:
// https://github.com/agsh/onvif/blob/master/lib/cam.js
CryptoPP::Base64Decoder decoder;
decoder.Put((byte*)nonce.data(), nonce.size());
std::vector<uint8_t> bytes(decoder.MaxRetrievable(),0);
decoder.Get(&bytes[0],bytes.size());
//
CryptoPP::SHA1 hash;
byte digest[CryptoPP::SHA1::DIGESTSIZE];
hash.Update(bytes.data(), bytes.size());
hash.Update((const byte*)dt.c_str(), dt.size());
hash.Update((const byte*)pwd.c_str(), pwd.size());
hash.Final(digest);
CryptoPP::Base64Encoder encoder;
encoder.Put(digest, CryptoPP::SHA1::DIGESTSIZE);
std::string hash64(encoder.MaxRetrievable(), 0);
encoder.Get((byte*)hash64.data(), hash64.size());
// generates woEIuU+ryXxcwkTZ9ktbKGeQ
std::cout << hash64 << std::endl;
}
Any thoughts on this one much appreciated.
[edit: remove C# references]
CryptoPP::Base64Decoder decoder;
decoder.Put((byte*)nonce.data(), nonce.size());
std::vector<uint8_t> bytes(decoder.MaxRetrievable(),0);
decoder.Get(&bytes[0],bytes.size());
Call MessageEnd:
Base64Decoder decoder;
decoder.Put((byte*)nonce.data(), nonce.size());
decoder.MessageEnd();
vector<uint8_t> bytes(decoder.MaxRetrievable(),0);
decoder.Get(&bytes[0],bytes.size());
Ditto:
Base64Encoder encoder;
encoder.Put(digest, 20);
encoder.MessageEnd();
string hash64(encoder.MaxRetrievable(), 0);
encoder.Get((byte*)hash64.data(), hash64.size());
Also see Base64Encoder | Missing Data and Base64Decoder | Missing Data on the Crypto++ wiki.
Nor indeed can I duplicate the result using any other approaches, like a full C# test bed using all of the .NET crypto resources.
I don't know C# as well as Crypto++, so I can't help with a C# example that works as expected with ONVIF authentication.
Here's the result I get:
$ g++ test.cxx -I. ./libcryptopp.a -o test.exe
$ ./test.exe
tuOSpGlFlIXsozq4HFNeeGeFLEI=
And the cat test.cxx:
#include <iostream>
#include <string>
#include <vector>
#include "base64.h"
#include "sha.h"
std::string nonce = "LKqI6G/AikKCQrN0zqZFlg==";
std::string dt = "2010-09-16T07:50:45Z";
std::string pwd = "userpassword";
int main(int argc, char* argv[])
{
CryptoPP::Base64Decoder decoder;
decoder.Put((byte*)nonce.data(), nonce.size());
decoder.MessageEnd();
std::vector<uint8_t> bytes(decoder.MaxRetrievable(),0);
decoder.Get(&bytes[0],bytes.size());
CryptoPP::SHA1 hash;
byte digest[CryptoPP::SHA1::DIGESTSIZE];
hash.Update(bytes.data(), bytes.size());
hash.Update((const byte*)dt.c_str(), dt.size());
hash.Update((const byte*)pwd.c_str(), pwd.size());
hash.Final(digest);
CryptoPP::Base64Encoder encoder;
encoder.Put(digest, 20);
encoder.MessageEnd();
std::string hash64(encoder.MaxRetrievable(), 0);
encoder.Get((byte*)hash64.data(), hash64.size());
std::cout << hash64 << std::endl;
return 0;
}
The following test code should theoretically give me the result from the NIST test suite of 58e2fccefa7e3061367f1d57a4e7455a , however a hexdump of the output yields 9eeaed13b5f591104e2cda197fb99eeaed13b5f591104e2cda197fb9 instead ?
#include <iostream>
#include <cstdio>
#include <polarssl/md.h>
#include <polarssl/entropy.h>
#include <polarssl/ctr_drbg.h>
#include <polarssl/cipher.h>
#include <cstdlib>
#include <fstream>
int main(int argc, char** argv) {
const cipher_info_t *cipher_info;
cipher_info = cipher_info_from_string( "AES-128-GCM" );
cipher_context_t cipher_ctx;
cipher_init_ctx (&cipher_ctx,cipher_info);
std::cout<<"KEYLEN"<<std::endl;
std::cout<<cipher_info->key_length<<std::endl;
std::cout<<"IVLEN"<<std::endl;
std::cout<<cipher_info->iv_size<<std::endl;
unsigned char key[cipher_info->key_length/8];
unsigned char iv[cipher_info->iv_size];
memset(key,0x00,cipher_info->key_length/8);
memset(iv,0x00,cipher_info->iv_size);
unsigned char iBuffer[10];
unsigned char oBuffer[1024];
size_t ilen, olen;
std::ofstream oFile2;
oFile2.open("testOut",std::ofstream::out | std::ofstream::trunc | std::ofstream::binary);
cipher_setkey( &cipher_ctx,key,cipher_info->key_length,POLARSSL_ENCRYPT);
cipher_set_iv( &cipher_ctx, iv, 16 );
cipher_reset( &cipher_ctx );
cipher_update( &cipher_ctx, iBuffer, sizeof(iBuffer), oBuffer, &olen );
oFile2 << oBuffer;
cipher_finish( &cipher_ctx, oBuffer, &olen );
oFile2 << oBuffer;
oFile2.close();
}
This is the nIST test :
Variable
Value
K 00000000000000000000000000000000
P
IV 000000000000000000000000
H 66e94bd4ef8a2c3b884cfa59ca342b2e
Yo 00000000000000000000000000000001
E ( K,Yo) 58e2fccefa7e3061367f1d57a4e7455a
len(A)||len(C) 00000000000000000000000000000000
GHASH (H,A,C) 00000000000000000000000000000000
C
T 58e2fccefa7e3061367f1d57a4e7455a
(test case No. 1 http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf)
I can see two immediate mistakes:
the plain text size is set to 10 bytes instead of no bytes at all - this makes the ciphertext too large and the authentication tag incorrect;
the IV is 12 bytes set to 0 instead of 16 bytes set to 0 - 12 is the default for GCM mode - this makes the ciphertext if any and authentication tag incorrect.
These issues are in the following lines:
unsigned char iBuffer[10];
...
cipher_update( &cipher_ctx, iBuffer, sizeof(iBuffer), oBuffer, &olen );
and
cipher_set_iv( &cipher_ctx, iv, 16 );
Furthermore, it seems like the API requires you to retrieve the tag separately using the ...write_tag... method. Currently you are only seeing the CTR ciphertext, not the authentication tag.