MbedTLS GCM Decryption Error - encryption

I have the C program below that tries to use the MbedTLS AES GCM functions to encrypt and decrypt. The encryption is running well but the decryption is abending with rc = -25344 (-0x6300) in mbedtls_cipher_check_tag(). The mbedtls_strerror returns "Last error was: -0x6300 - CIPHER - Authentication failed (for AEAD modes)" for that return code.
Although the documentation says to put it after the mbedtls_cipher_finish(), I've tried to change the function's place (as indicated in the code) without sucess.
What am I doing wrong, any idea ??
Any help is very valuable.
Thanks in advance
Here the code:
//#
//# AES 128 GCM - MbedTLS
//#
#include <mbedtls/cipher.h>
#include <mbedtls/gcm.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "etss.h"
#define PLAIN_SIZE 1024
#define CRYPT_SIZE 1032
key128 k;
iv16 iv;
aad16 aad;
tag16 tag;
int Decrypta (FILE * fInput, FILE * fOutput)
{
int conta = 0, rc = 0;
int nBytesWorked = 0, nGCMfinal = 0;
int nBytesRead = 0, nBytesWritten = 0;
int cIn = 0, cOut = 0, cWorked = 0;
unsigned char sPureBuff[PLAIN_SIZE] __attribute__((aligned(16))), sCiphBuff[CRYPT_SIZE] __attribute__((aligned(16)));
unsigned char *pPureBuff __attribute__((aligned(16)));
unsigned char *pCiphBuff __attribute__((aligned(16)));
unsigned char *pTag = tag.data;
pPureBuff = sPureBuff;
pCiphBuff = sCiphBuff;
mbedtls_cipher_context_t ctx;
mbedtls_cipher_init (&ctx);
rc = mbedtls_cipher_setup (&ctx, mbedtls_cipher_info_from_values(MBEDTLS_CIPHER_ID_AES, k.size*8, MBEDTLS_MODE_GCM));
if ( rc != 0 )
{
printf ("Setup - Context preparation error (rc = %d). \n", rc);
return rc;
}
rc = mbedtls_cipher_setkey (&ctx, k.data, k.size*8, MBEDTLS_DECRYPT);
if ( rc != 0 )
{
printf ("Set Key - Context preparation error (rc = %d). \n", rc);
return rc;
}
rc = mbedtls_cipher_set_iv (&ctx, iv.data, iv.size);
if ( rc != 0 )
{
printf ("Set IV - Context preparation error (rc = %d). \n", rc);
return rc;
}
// rc = mbedtls_cipher_check_tag (&ctx, pTag, (size_t) tag.size);
//
// if ( rc != 0 )
// {
// printf ("Decryption - Error in check_tag() (rc=%d).\n",rc);
// return rc;
// }
rc = mbedtls_cipher_reset (&ctx);
if ( rc != 0 )
{
printf ("Reset - Context preparation error (rc = %d). \n", rc);
return rc;
}
rc = mbedtls_cipher_update_ad (&ctx, aad.data, aad.size);
if ( rc != 0 )
{
printf ("Set AAD - Context preparation error (rc = %d). \n", rc);
return rc;
}
memset(pCiphBuff, 0, CRYPT_SIZE);
memset(pPureBuff, 0, PLAIN_SIZE);
if ( (rc = ReadFile (fInput, &pCiphBuff, 1, CRYPT_SIZE, &nBytesRead)) )
{
printf ("Decryption - Input file reading error (rc = %d). \n", rc);
return rc;
}
while ( nBytesRead > 0 )
{
cIn += nBytesRead;
nBytesWorked = 0;
rc = mbedtls_cipher_update (&ctx, sCiphBuff, nBytesRead, sPureBuff, (size_t *) &nBytesWorked);
if ( rc != 0 )
{
printf ("Decryption - Error in DecryptUpdate() (rc = %d).\n", rc);
return rc;
}
cWorked += nBytesWorked;
// Count decryptions
conta++;
if ( nBytesWorked != 0 )
{
if ( (rc = WriteFile (fOutput, sPureBuff, 1, cWorked, &nBytesWritten)) )
{
printf ("Decryption - Output file writing error (rc = %d).\n", rc);
return rc;
}
pPureBuff = sPureBuff;
memset(pPureBuff, 0, PLAIN_SIZE);
cOut += nBytesWritten;
cWorked = 0;
}
if ( (rc = ReadFile (fInput, &pCiphBuff, 1, CRYPT_SIZE, &nBytesRead)) )
{
printf ("Decryption - Input file reading error (rc = %d). \n", rc);
return rc;
}
}
// rc = mbedtls_cipher_check_tag (&ctx, pTag, (size_t) tag.size);
//
// if ( rc != 0 )
// {
// printf ("Decryption - Error in check_tag() (rc=%d).\n",rc);
// return rc;
// }
pPureBuff += cWorked;
rc = mbedtls_cipher_finish (&ctx, pPureBuff, (size_t *) &nGCMfinal);
if ( rc != 0 )
{
printf ("Decryption - Error in DecryptFinal() (rc=%d).\n",rc);
return rc;
}
// Count decryptions
conta++;
rc = mbedtls_cipher_check_tag (&ctx, pTag, (size_t) tag.size);
if ( rc != 0 )
{
printf ("Decryption - Error in check_tag() (rc=%d).\n",rc);
return rc;
}
cWorked += nBytesWorked;
if ( (rc = WriteFile (fOutput, sPureBuff, 1, cWorked, &nBytesWritten)) )
{
printf ("Decryption - Output file writing error (rc = %d).\n", rc);
return rc;
}
cOut += nBytesWritten;
printf("\tD %d cIn = %d cOut = %d\n\n", conta, cIn, cOut);
mbedtls_cipher_free (&ctx);
return 0;
}
int Encrypta (FILE * fInput, FILE * fOutput)
{
int conta = 0, rc = 0;
int nBytesWorked = 0, nGCMfinal = 0;
int nBytesRead = 0, nBytesWritten = 0;
int cIn = 0, cOut = 0, cWorked = 0;
unsigned char sPureBuff[PLAIN_SIZE] __attribute__((aligned(16))), sCiphBuff[CRYPT_SIZE] __attribute__((aligned(16)));
unsigned char *pPureBuff __attribute__((aligned(16)));
unsigned char *pCiphBuff __attribute__((aligned(16)));
unsigned char *pTag = tag.data;
pPureBuff = sPureBuff;
pCiphBuff = sCiphBuff;
mbedtls_cipher_context_t ctx;
mbedtls_cipher_init (&ctx);
rc = mbedtls_cipher_setup (&ctx, mbedtls_cipher_info_from_values(MBEDTLS_CIPHER_ID_AES, k.size*8, MBEDTLS_MODE_GCM));
if ( rc != 0 )
{
printf ("Setup - Context preparation error (rc = %d). \n", rc);
return rc;
}
rc = mbedtls_cipher_setkey (&ctx, k.data, k.size*8, MBEDTLS_ENCRYPT);
if ( rc != 0 )
{
printf ("Set Key - Context preparation error (rc = %d). \n", rc);
return rc;
}
rc = mbedtls_cipher_set_iv (&ctx, iv.data, iv.size);
if ( rc != 0 )
{
printf ("Set IV - Context preparation error (rc = %d). \n", rc);
return rc;
}
rc = mbedtls_cipher_reset (&ctx);
if ( rc != 0 )
{
printf ("Reset - Context preparation error (rc = %d). \n", rc);
return rc;
}
rc = mbedtls_cipher_update_ad (&ctx, aad.data, aad.size);
if ( rc != 0 )
{
printf ("Set AAD - Context preparation error (rc = %d). \n", rc);
return rc;
}
memset(pPureBuff, 0, PLAIN_SIZE);
memset(pCiphBuff, 0, CRYPT_SIZE);
if ( (rc = ReadFile (fInput, &pPureBuff, 1, PLAIN_SIZE, &nBytesRead)) )
{
printf ("Encryption - Input file reading error (rc = %d). \n", rc);
return rc;
}
while ( nBytesRead > 0 )
{
cIn += nBytesRead;
pCiphBuff += cWorked;
rc = mbedtls_cipher_update (&ctx, sPureBuff, nBytesRead, sCiphBuff, (size_t *) &nBytesWorked);
if ( rc != 0 )
{
printf ("Encryption - Error in EncryptUpdate() (rc = %d).\n", rc);
return rc;
}
cWorked += nBytesWorked;
// Count encryptions
conta++;
if ( nBytesWorked != 0 )
{
if ( (rc = WriteFile (fOutput, sCiphBuff, 1, cWorked, &nBytesWritten)) )
{
printf ("Encryption - Output file writing error (rc = %d).\n", rc);
return rc;
}
pCiphBuff = sCiphBuff;
memset(pCiphBuff, 0, CRYPT_SIZE);
cOut += nBytesWritten;
cWorked = 0;
}
if ( (rc = ReadFile (fInput, &pPureBuff, 1, PLAIN_SIZE, &nBytesRead)) )
{
printf ("Encryption - Input file reading error (rc = %d). \n", rc);
return rc;
}
}
pCiphBuff += cWorked;
rc = mbedtls_cipher_finish (&ctx, pCiphBuff, (size_t *) &nGCMfinal);
if ( rc != 0 )
{
printf ("Encryption - Error in EncryptFinal() (rc=%d).\n",rc);
return rc;
}
// Count encryptions
conta++;
rc = mbedtls_cipher_write_tag (&ctx, pTag, (size_t) tag.size);
if ( rc != 0 )
{
printf ("Encryption - Error in write_tag() (rc=%d).\n",rc);
return rc;
}
cWorked += nBytesWorked;
if ( (rc = WriteFile (fOutput, sCiphBuff, 1, cWorked, &nBytesWritten)) )
{
printf ("Encryption - Output file writing error (rc = %d).\n", rc);
return rc;
}
cOut += nBytesWritten;
printf("\tE %d cIn = %d cOut = %d\n\n", conta, cIn, cOut);
mbedtls_cipher_free (&ctx);
return 0;
}
int main (int argc, char *argv[])
{
FILE *fPlain = NULL, *fEncrypt = NULL, *fDecrypt = NULL;
k.size = 16;
unsigned char inKey[16] = {0x9A, 0x59, 0x4E, 0xFA, 0x2C, 0x40, 0xBC, 0xC1, 0x2A, 0x05, 0x64, 0x43, 0xAC, 0x0C, 0xC1, 0xC2};
iv.size = 16;
unsigned char inIV[16] = {0x57, 0x1D, 0x32, 0xCE, 0x4F, 0x43, 0x17, 0x38, 0xE5, 0x52, 0x69, 0xE2, 0x18, 0xD1, 0x32, 0x09};
aad.size = 16; tag.size = 16;
unsigned char inAAD[16] = {0x9A, 0x1D, 0x4E, 0xCE, 0x2C, 0x43, 0xBC, 0x38, 0x2A, 0x52, 0x64, 0xE2, 0xAC, 0xD1, 0xC1, 0x09};
strncpy((char *) k.data, (const char *) inKey, k.size);
strncpy((char *) iv.data, (const char *) inIV, iv.size);
strncpy((char *) aad.data, (const char *) inAAD, aad.size);
int rc = 0;
if ( (rc = OpenFile (&fPlain, argv[1], "r")) )
{
printf ("GCM128-M - Open input plain text file %s error (rc = %d).\n", argv[1], rc);
return rc;
}
fEncrypt = fopen (argv[2], "wb+");
rc = errno;
if ( fEncrypt == NULL )
{
printf ("GCM128-M - Open output encrypt text file %s error (rc = %d).\n", argv[2], rc);
return rc;
}
printf("\n>> Encrypting AES GCM 128 ...\n\n");
Encrypta (fPlain, fEncrypt);
CloseFile(fPlain);
CloseFile(fEncrypt);
fEncrypt = fopen (argv[2], "rb+");
rc = errno;
if ( fEncrypt == NULL )
{
printf ("GCM128-M - Open input encrypt text file %s error (rc = %d).\n", argv[2], rc);
return rc;
}
if ( (rc = OpenFile (&fDecrypt, argv[3], "w")) )
{
printf ("GCM128-M - Open output decrypt text file %s error (rc = %d).\n", argv[3], rc);
return rc;
}
printf("\n>> Decrypting AES GCM 128 ...\n\n");
Decrypta (fEncrypt, fDecrypt);
CloseFile(fEncrypt);
CloseFile(fDecrypt);
return 0;
}
The etss.h (asked by Gilles) is:
#ifndef ETSS_H_
#define ETSS_H_
typedef struct st_key128 {
unsigned char data[16];
int size;
} key128;
typedef struct st_key192 {
unsigned char data[24];
int size;
} key192;
typedef struct st_key256 {
unsigned char data[32];
int size;
} key256;
typedef struct st_iv8 {
unsigned char data[8];
int size;
} iv8;
typedef struct st_iv16 {
unsigned char data[16];
int size;
} iv16;
typedef struct st_iv32 {
unsigned char data[32];
int size;
} iv32;
typedef struct st_aad8 {
unsigned char data[8];
int size;
} aad8;
typedef struct st_aad16 {
unsigned char data[16];
int size;
} aad16;
typedef struct st_aad32 {
unsigned char data[32];
int size;
} aad32;
typedef struct st_tag8 {
unsigned char data[8];
int size;
} tag8;
typedef struct st_tag16 {
unsigned char data[16];
int size;
} tag16;
int InitKey128(key128 * key);
int InitKey192(key192 * key);
int InitKey256(key256 * key);
int InitIV8(iv8 * iv);
int InitIV16(iv16 * iv);
int InitIV32(iv32 * iv);
int InitAAD8(aad8 * iv);
int InitAAD16(aad16 * iv);
int InitAAD32(aad32 * iv);
int InitTAG8(tag8 * iv);
int InitTAG16(tag16 * iv);
int SetKey128(key128 * key, char * keyValue);
int SetKey192(key192 * key, char * keyValue);
int SetKey256(key256 * key, char * keyValue);
int SetIV8(iv8 * iv, char * ivValue);
int SetIV16(iv16 * iv, char * ivValue);
int SetIV32(iv32 * iv, char * ivValue);
int SetAAD8(aad8 * aad, char * aadValue);
int SetAAD16(aad16 * aad, char * aadValue);
int SetAAD32(aad32 * aad, char * aadValue);
int SetTAG8(tag8 * tag, char * tagValue);
int SetTAG16(tag16 * tag, char * tagValue);
int OpenFile(FILE ** handler, char * name, char * mode);
int ReadFile(FILE * handler, unsigned char ** buffer, int regsize, int blocking, int * bytesread);
int WriteFile(FILE * handler, unsigned char * buffer, int regsize, int blocking, int * byteswritten);
int CloseFile(FILE * handler);
int DisplayChs(unsigned char * buffer, int size);
int PrintChs(FILE * handler, unsigned char * buffer, int size, int flag); // flag = 0 => don't DisplayChs
int DisplayNibbles(unsigned char * buffer, int size);
int DisplayHex(unsigned char * buffer, int size);
int PrintHex(FILE * handler, unsigned char * buffer, int size, int flag); // flag = 0 => don't DisplayHex
int Generate_Key128 (key128 *k) ;
int Generate_Key192 (key192 *k) ;
int Generate_Key256 (key256 *k) ;
int Generate_Nonce8 (iv8 *iv) ;
int Generate_Nonce16 (iv16 *iv) ;
int Generate_Nonce32 (iv32 *iv) ;
#endif /* ETSS_H_ */
Notice that the hexcodes are not generate here, just manually set.
Thanks again.

On AEAD algorithms, the encrypted buffer includes the tag. This is why CRYPT_SIZE is 8 bytes longer than PLAIN_SIZE. I believe you are trying to decrypt the full cipher buffer, including the tag.
In your Decrypta() function, please try the mbedtls_cipher_update() loop only for CRYPT_SIZE - tag.size bytes.
After that, get the tag from the cipher buffer, and use it for mbedtls_cipher_check_tag() function.

Related

Why does code not work after using fopen() command

I created FILE *ptr to read a file, and after I declare ptr =fopen("file_name.txt", "r");
none of my code written afterwards will work.
BELOW IS SOME OF THE ACTUAL CODE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define MAXFILE 30
#define MAX 50
typedef struct Student
{
int stdid;
char *fname;
char *lname;
int day;
int month;
int year;
}Student;
typedef struct Course
{
char *cid;
char *cname;
float credit;
}Course;
typedef struct Enrollment
{
int stdid;
int cid;
char *semester;
float score;
}Enrollment;
int main()
{
char stud[MAXFILE], courses[MAXFILE], enroll[MAXFILE];
printf("TESTING1");
scanf("%s %s %s",stud,courses,enroll);
int studnum,coursenum,enrollnum;
FILE *st, *cou, *enr;
st = fopen("stud","r");
cou = fopen("courses","r");
enr = fopen("enroll","r");
printf("TESTING2");
if(st==NULL || cou == NULL || enr== NULL)
{
printf("unable to open file\n");
exit(1);
}
fscanf(st,"%d",&studnum);
Student *students = (Student*)(malloc(sizeof(Student) * studnum));
for(int i =0; i<studnum;i++)
{
char ftemp[MAX],ltemp[MAX];
int fir, las;
fscanf(st,"%d %s %s %d %d %d",&students[i].stdid, ftemp, ltemp, &students[i].day, &students[i].month, &students[i].year);
fir = strlen(ftemp)+1;
las = strlen(ltemp)+1;
strcpy(students[i].fname,ftemp);
strcpy(students[i].lname,ltemp);
students[i].fname = malloc(fir * sizeof(char));
students[i].lname = malloc(las * sizeof(char));
strcpy(students[i].fname,ftemp);
strcpy(students[i].lname,ltemp);
}
//reading the students.txt file and filling out Student type array with data;
printf("TESTING3");
fscanf(cou,"%d",&coursenum);
Course *course = (Course*)(malloc(sizeof(Course)*coursenum));
for(int i =0; i<coursenum;i++)
{
char cidtemp[MAX], cntemp[MAX];
int tempcid, tempcn;
fscanf(cou,"%s %s %f",cidtemp, cntemp, &course[i].credit);
tempcid = strlen(cidtemp)+1;
tempcn = strlen(cntemp)+1;
course[i].cid = malloc(tempcid*sizeof(char));
course[i].cname = malloc(tempcn * sizeof(char));
strcpy(course[i].cid,cidtemp);
strcpy(course[i].cname, cntemp);
}
//reading the couses.txt file and filling out an array of type Course with the data
printf("TESTING4");
fscanf(enr,"%d",&enrollnum);
Enrollment *enrollment = (Enrollment*)(malloc(sizeof(Enrollment)*enrollnum));
for(int i =0; i<enrollnum; i++)
{
int stdid;
int cid;
char *semester;
float score;
char semest[MAX];
int semtemp;
fscanf(enr,"%d %d %s %f",&enrollment[i].stdid, &enrollment[i].cid, semest, &enrollment[i].score);
semtemp = strlen(semest)+1;
enrollment[i].semester = malloc(semtemp * sizeof(char));
strcpy(enrollment[i].semester, semest);
printf("%d\t%d\t%s\t%.0f \n", enrollment[i].stdid, enrollment[i].cid, enrollment[i].semester, enrollment[i].score);
}
//reading the enrollment files and fill out at array of type Enrollment
//testing new arrays
printf("%d", enrollnum);
for(int i = 0; i<enrollnum; i ++)
{
printf("%d\t%d\t%s\t%.0f \n", enrollment[i].stdid, enrollment[i].cid, enrollment[i].semester, enrollment[i].score);
}
fclose(st);
fclose(cou);
fclose(enr);
for(int i =0; i < studnum;i++)
{
free(students[i].fname);
free(students[i].lname);
}
free(students);
for(int i =0; i < coursenum;i++)
{
free(course[i].cid);
free(course[i].cname);
}
free(course);
for(int i =0; i < enrollnum;i++)
{
free(enrollment[i].semester);
}
free(enrollment);
return 0;
}

Cipher text generated by OpenSSL and Windows CNG is different for AES-128-CFB

I am encrypting the same plain text with AES-128-CFB but ciphertext generated by "Windows Cryptography API: Next Generation" and OpenSSL are different for the same IV, and key.
Plain Text: The quick brown fox jumps over the lazy dog
IV: 1234567887654321
Key: 1234567887654321
Cipher Text generated by Windows CNG in Hex: 279CB0C2FD67B37F33A861CDDAFBEDCEEAEFC68FD5B3478E67E4A936BA7CFE75DDBAD370A1E4D6CDC3455E2F4E188A9C
Cipher Text length generated by Windows CNG: 48 Bytes
Cipher Text generated by OpenSSL in Hex: 279CB0C2FD67B37F33A861CDDAFBEDCEEAEFC68FD5B3478E67E4A936BA7CFE75DDBAD370A1E4D6CDC3455E
Cipher Text length generated by Windows CNG: 43 Bytes
Windows CNG adding extra 5 bytes(2F4E188A9C) at the end, I thought it is due to padding and sent dwFlags value as 0 instead of BCRYPT_BLOCK_PADDING then BCryptEncrypt API call failing with error code 0xc0000206/STATUS_INVALID_BUFFER_SIZE.
Windows CNG code:
#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#pragma comment(lib, "bcrypt.lib")
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
void
hexdump(const char *msg, const unsigned char *in, unsigned int len)
{
printf("%s [%d][", msg, len);
for (; len > 0; len--, in++) {
printf("%02X", *in);
}
printf("]\n");
}
const BYTE rgbPlaintext[] = "The quick brown fox jumps over the lazy dog";
static const BYTE rgbIV[] = "1234567887654321";
static const BYTE rgbAES128Key[] = "0123456789abcdefghijklmnopqrstuv";
const int ival_len = 16;
const int key_len = 16;
const DWORD block_len = 16;
void __cdecl wmain(
int argc,
__in_ecount(argc) LPWSTR *wargv)
{
BCRYPT_ALG_HANDLE hAesAlg = NULL;
BCRYPT_KEY_HANDLE hKey = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
DWORD cbCipherText = 0,
cbData = 0,
cbKeyObject = 0,
cbBlockLen = 0,
cbBlob = 0;
PBYTE pbCipherText = NULL,
pbKeyObject = NULL,
pbIV = NULL,
pbBlob = NULL;
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(wargv);
if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
&hAesAlg,
BCRYPT_AES_ALGORITHM,
NULL,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
goto Cleanup;
}
if(!NT_SUCCESS(status = BCryptGetProperty(
hAesAlg,
BCRYPT_OBJECT_LENGTH,
(PBYTE)&cbKeyObject,
sizeof(DWORD),
&cbData,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
goto Cleanup;
}
pbKeyObject = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbKeyObject);
if(NULL == pbKeyObject)
{
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
if (ival_len > sizeof (rgbIV))
{
wprintf (L"**** block length is longer than the provided IV length\n");
goto Cleanup;
}
if(ival_len > 0)
{
pbIV= (PBYTE) HeapAlloc (GetProcessHeap (), 0, ival_len + 1);
if(NULL == pbIV)
{
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
strncpy(pbIV,rgbIV,ival_len);
pbIV[ival_len]='\0';
}
if(!NT_SUCCESS(status = BCryptSetProperty(
hAesAlg,
BCRYPT_CHAINING_MODE,
(PBYTE)BCRYPT_CHAIN_MODE_CFB,
sizeof(BCRYPT_CHAIN_MODE_CFB),
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptSetProperty\n", status);
goto Cleanup;
}
if(!NT_SUCCESS(status = BCryptGetProperty(
hAesAlg,
BCRYPT_BLOCK_LENGTH,
(PBYTE)&cbBlockLen,
sizeof(DWORD),
&cbData,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
goto Cleanup;
}
if(!NT_SUCCESS(status = BCryptGenerateSymmetricKey(
hAesAlg,
&hKey,
pbKeyObject,
cbKeyObject,
(PBYTE)rgbAES128Key,
key_len,
0)))
{
wprintf(L"**** Error 0x%x returned by BCryptGenerateSymmetricKey\n ", status);
fprintf(stderr, "\nError number <%x>", GetLastError());
goto Cleanup;
}
if (!NT_SUCCESS(status = BCryptSetProperty(hKey,
BCRYPT_MESSAGE_BLOCK_LENGTH,
(PBYTE)&block_len,
sizeof(DWORD),
0))) {
wprintf(L"**** Error 0x%x returned by BCryptSetProperty\n ", status);
fprintf(stderr, "\nError number <%x>", GetLastError());
goto Cleanup;
}
printf("\nplan text is [%d][%s]\n", sizeof(rgbPlaintext) - 1, rgbPlaintext);
if(!NT_SUCCESS(status = BCryptEncrypt(
hKey,
rgbPlaintext,
sizeof(rgbPlaintext) - 1,
NULL,
pbIV,
ival_len,
NULL,
0,
&cbCipherText,
BCRYPT_BLOCK_PADDING)))
{
wprintf(L"\n**** Error 1 0x%x returned by BCryptEncrypt\n", status);
goto Cleanup;
}
pbCipherText = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbCipherText);
if(NULL == pbCipherText)
{
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
// Use the key to encrypt the plaintext buffer.
// For block sized messages, block padding will add an extra block.
if(!NT_SUCCESS(status = BCryptEncrypt(
hKey,
rgbPlaintext,
sizeof(rgbPlaintext) - 1,
NULL,
pbIV,
ival_len,
pbCipherText,
cbCipherText,
&cbData,
BCRYPT_BLOCK_PADDING)))
{
wprintf(L"**** Error 2 0x%x returned by BCryptEncrypt\n", status);
goto Cleanup;
}
hexdump("cipher is", pbCipherText, cbCipherText);
Cleanup:
if(hAesAlg)
{
BCryptCloseAlgorithmProvider(hAesAlg,0);
}
if (hKey)
{
BCryptDestroyKey(hKey);
}
if(pbCipherText)
{
HeapFree(GetProcessHeap(), 0, pbCipherText);
}
if(pbKeyObject)
{
HeapFree(GetProcessHeap(), 0, pbKeyObject);
}
if(pbIV)
{
HeapFree(GetProcessHeap(), 0, pbIV);
}
}
OpenSSL Code:
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
void
hexdump(const char *msg, const unsigned char *in, unsigned int len)
{
printf("%s [%d][", msg, len);
for (; len > 0; len--, in++) {
printf("%02X", *in);
}
printf("]\n");
}
int main(void)
{
/* A 256 bit key */
unsigned char *key = (unsigned char *)"0123456789abcdefghijklmnopqrstuv";
/* A 128 bit IV */
unsigned char *iv = (unsigned char *)"1234567887654321";
/* Message to be encrypted */
unsigned char *plaintext =
(unsigned char *)"The quick brown fox jumps over the lazy dog12312";
unsigned char ciphertext[128];
int ciphertextLen = encrypt(plaintext, strlen ((char *)plaintext), key, iv, ciphertext);
hexdump("cipher value is:", ciphertext, ciphertextLen);
return 0;
}
void handleErrors(void)
{
ERR_print_errors_fp(stderr);
abort();
}
int encrypt(unsigned char *plaintext,
int plaintext_len,
unsigned char *key,
unsigned char *iv,
unsigned char *ciphertext)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertextLen;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_cfb(), NULL, key, iv))
handleErrors();
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertextLen = len;
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
handleErrors();
ciphertextLen += len;
EVP_CIPHER_CTX_free(ctx);
return ciphertextLen;
}

how to tokenize a string in arduino

i am using arduino due. what i am trying to do is to receive a string at serial. like this one:
COMSTEP 789 665 432 END
if the string starts with comstep, then to tokenize the string and get an integer array {789, 665, 432}.
is there anyway to do that?
P.S: im a noob at programming, so any help is appreciated.
I have a function that I wrote long ago to parse strings up in an easy manner. It is in use on several of my Arduino projects.
Sample usage:
char pinStr[3];
char valueStr[7];
int pinNumber, value;
getstrfld (parms_in, 0, 0, (char *)",", pinStr);
getstrfld (parms_in, 1, 0, (char *)",", valueStr);
pinNumber = atoi (pinStr);
value = atoi (valueStr);
The functions:
// My old stand-by to break delimited strings up.
char * getstrfld (char *strbuf, int fldno, int ofset, char *sep, char *retstr)
{
char *offset, *strptr;
int curfld;
offset = strptr = (char *)NULL;
curfld = 0;
strbuf += ofset;
while (*strbuf) {
strptr = !offset ? strbuf : offset;
offset = strpbrk ((!offset ? strbuf : offset), sep);
if (offset) {
offset++;
} else if (curfld != fldno) {
*retstr = 0;
break;
}
if (curfld == fldno) {
strncpy (retstr, strptr,
(int)(!offset ? strlen (strptr)+ 1 :
(int)(offset - strptr)));
if (offset)
retstr[offset - strptr - 1] = 0;
break;
}
curfld++;
}
return retstr;
}
// Included because strpbrk is not in the arduino gcc/g++ libraries
// Or I just could not find it :)
char * strpbrk (const char *s1, const char *s2)
{
const char *c = s2;
if (!*s1) {
return (char *) NULL;
}
while (*s1) {
for (c = s2; *c; c++) {
if (*s1 == *c)
break;
}
if (*c)
break;
s1++;
}
if (*c == '\0')
s1 = NULL;
return (char *) s1;
}
A light-weight approach (no strict checks on valid parses of the integers and ignoring any list elements past a fixed maximum):
char buf[32] = "COMSTEP 789 665 432 END"; // assume this has just been read
int res[8], nres = 0;
bool inlist = false;
for (char *p = strtok(buf, " "); p; p = strtok(0, " "))
if (inlist)
{
if (!strcmp(p, "END"))
{
inlist = false;
break;
}
else if (nres < sizeof(res) / sizeof(*res))
res[nres++] = atoi(p);
}
else if (!strcmp(p, "COMSTEP"))
inlist = true;
if (!inlist)
for (size_t i = 0; i < nres; ++i)
printf("%d%s", res[i], i + 1 < nres ? " " : "\n"); // do whatever

OpenCL clCreateKernel throws CL_INVALID_PROGRAM_EXECUTABLE

im new with OpenCL, I have a problem in clCreateKernel, it throws CL_INVALID_PROGRAM_EXECUTABLE, could anybody help, the code is based on http://www.cs.bris.ac.uk/home/simonm/workshops/OpenCL_lecture3.pdf , the last optimization
Here is the code:
#define ORDER 10 // Order of the square matrices A, B, and C
#define AVAL 3.0 // A elements are constant and equal to AVAL
#define BVAL 5.0 // B elements are constant and equal to BVAL
#define TOL (0.001) // tolerance used in floating point comparisons
#define DIM 2 // Max dim for NDRange
#define COUNT 1 // number of times to do each multiplication
#define SUCCESS 1
#define FAILURE 0
// Funciones Auxiliares
void initmat(int Mdim, int Ndim, int Pdim, float *A, float *B, float *C)
{
int i, j;
/* Initialize matrices */
for (i = 0; i < Ndim; i++)
for (j = 0; j < Pdim; j++)
A[i*Ndim+j] = AVAL;
for (i = 0; i < Pdim; i++)
for (j = 0; j < Mdim; j++)
B[i*Pdim+j] = BVAL;
for (i = 0; i < Ndim; i++)
for (j = 0; j < Mdim; j++)
C[i*Ndim+j] = 0.0f;
}
// Definicion de la funcion:
char * readKernel(void)
{
size_t *source_length;
FILE *fp = fopen("kernel.cl", "r");
if (fp == NULL)
{
printf("Cannot Open Kernel.cl\n");
}
else
{
printf("Kernel.cl Opened\n");
}
fseek(fp, 0, SEEK_END);
source_length[0] = ftell(fp);
if (source_length[0] == 0)
{
printf("Kernel.cl is empty\n");
}
else
{
printf("Kernel.cl length: %zu bytes\n", source_length[0]);
}
char *source = (char*) calloc(source_length[0] + 1, 1);
if (source == 0)
{
printf("Memory allocation failed");
}
fseek(fp, 0, SEEK_SET);
fread(source, 1, source_length[0], fp);
printf("Kernel.cl Read\n");
return source;
}
int main(int argc, char **argv)
{
// Declare and iniciate data
float *A, *B, *C;
int Mdim, Ndim, Pdim;
int err, szA, szB, szC;
size_t global[DIM];
size_t local[DIM];
cl_device_id device_id;
cl_context context;
cl_command_queue commands;
cl_program program;
cl_kernel kernel;
cl_uint nd;
cl_mem a_in, b_in, c_out;
Ndim = ORDER;
Pdim = ORDER;
Mdim = ORDER;
szA = Ndim*Pdim;
szB = Pdim*Mdim;
szC = Ndim*Mdim;
A = (float *)malloc(szA*sizeof(float));
B = (float *)malloc(szB*sizeof(float));
C = (float *)malloc(szC*sizeof(float));
const char* C_elem_KernelSource =
"__kernel \n"
"void mmul( \n"
" const int Mdim, \n"
" const int Ndim, \n"
" const int Pdim, \n"
" __global float* A, \n"
" __global float* B, \n"
" __global float* C, \n"
" __local float* Bwrk) \n"
"{ \n"
" int k,j; \n"
" int i = get_global_id(0); \n"
" int iloc = get_local_id(0); \n"
" int nloc = get_local_size(0); \n"
" float Awrk[10]; \n"
" float tmp; \n"
" for (k=0; k<Pdim; k++) \n"
" Awrk[k] = A[i*Ndim+k]; \n"
" for (j=0; j<Mdim; j++){ \n"
" for (k=iloc; k<Pdim; k=k+nloc) \n"
" Bwrk[k] = B[k*Pdim+j]; \n"
" barrier(CLK_LOCAL_MEM_FENCE); \n"
" tmp = 0.0f; \n"
" for (k=0; k<Pdim; k++) \n"
" tmp += Awrk[k] * Bwrk[k]; \n"
" C[i*Ndim+j] += tmp; \n"
"} \n"
;
initmat(Mdim, Ndim, Pdim, A, B, C);
// Setup the plataform
cl_uint num_platforms;
if(clGetPlatformIDs(0, NULL, &num_platforms) != CL_SUCCESS)
{
printf("Unable to get platform!\n");
}else{
printf("Plataformas Disponibles: %u \n", num_platforms);
}
//Identificador
cl_platform_id platform_id;
clGetPlatformIDs(1, &platform_id, &num_platforms);
printf("Plataformas creada\n");
err = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id, NULL);
if (err==CL_SUCCESS){
printf("Device creado \n");
}else {
printf("Error %d \n", err);
}
context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &err);
if (err==CL_SUCCESS){
printf("Contexto creado \n");
}else {
printf("Error creando contexto \n");
}
commands = clCreateCommandQueue(context, device_id, 0, &err);
if (err==CL_SUCCESS){
printf("cola de comandos creadas \n");
}else {
printf("Error creando cola de comandos \n");
}
// Setup buffers and write A and B matrices to the device memory
a_in = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(float) * szA, NULL, NULL);
b_in = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(float) * szB, NULL, NULL);
c_out = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(float) * szC, NULL, NULL);
err = clEnqueueWriteBuffer(commands, a_in, CL_TRUE, 0, sizeof(float) * szA, A, 0, NULL, NULL);
err = clEnqueueWriteBuffer(commands, b_in, CL_TRUE, 0, sizeof(float) * szB, B, 0, NULL, NULL);
// Build the program, define the kernel and setup arguments
program = clCreateProgramWithSource(context, 1, (const char **) &C_elem_KernelSource, NULL, &err);
if (err==CL_SUCCESS){
printf("programa creado \n");
}else {
printf("Error generado %d creando programa\n", err);
}
//Compila el programa en el dispositivo elegido
clBuildProgram(program, 1, &device_id, NULL, NULL, NULL );
if (err==CL_SUCCESS){
printf("programa compilado 1\n");
}else {
printf("Error generado %d compilando programa 1\n", err);
}
kernel = clCreateKernel(program, "mmul", &err);
if (err==CL_SUCCESS){
printf("Kernel creado \n");
}else {
printf("Error generado %d creando kernel\n", err);
}
err = clSetKernelArg(kernel, 0, sizeof(int), &Mdim);
err |= clSetKernelArg(kernel, 1, sizeof(int), &Ndim);
err |= clSetKernelArg(kernel, 2, sizeof(int), &Pdim);
err |= clSetKernelArg(kernel, 3, sizeof(cl_mem), &a_in);
err |= clSetKernelArg(kernel, 4, sizeof(cl_mem), &b_in);
err |= clSetKernelArg(kernel, 5, sizeof(cl_mem), &c_out);
err |= clSetKernelArg(kernel, 6, sizeof(float)*Pdim, NULL);
if (err==CL_SUCCESS){
printf("Argumentos del Kernel configurados \n");
}else {
printf("Error configurando argumentos del kernel \n");
}
//Run the kernel and collect results
// 1D ND Range set to dimensions of C matrix
//Local Dim set to 250 so number of work-groups match number of
//compute units (4 in this case) for our order 1000 matrices
//Pass local memory to kernels. This requires a change to the kernel
//argument list … a new call to clSetKernelArg is needed
printf("Encolando Kernel:\n");
global[0] = (size_t) Ndim; global[1] = (size_t) Mdim; local[0] = (size_t) 2;
err = clEnqueueNDRangeKernel(commands, kernel, 1, NULL, global, local, 0, NULL, NULL);
if (err==CL_SUCCESS){
printf("Kernel enviado a device \n");
}else {
printf("Error enviando kernel a device \n");
}
clFinish(commands);
err = clEnqueueReadBuffer(commands, c_out, CL_TRUE, 0, sizeof(float) * szC, C, 0, NULL, NULL );
//test_results(A, B, c_out);
}
Thanks
The main problem is that the open brace on line 112 has no matching closing brace:
" for (j=0; j<Mdim; j++){ \n"
Also note that the pointer declared on line 34 is used without initialization:
size_t *source_length;
On line 170, an err= should be added to the clBuildProgram() call so that the error checking works as intended. Then you can add logic to use clGetProgramBuildInfo() to get details in the case of a build fail.

openCL simple add vector returns gargabe values

Here is my attempt to write a opencl code to add 2 vectors
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif
#define MAX_SOURCE_SIZE (0x100000)
//24/12
//data structure platform, device, context,program, kernel, command queue
void main()
{
/////////////////////////////////////////////////////////////////////
//PLATFORM QUERY:
/////////////////////////////////////////////////////////////////////
//clGetPlatformIDs(num_entries, platforms, &num_platforms);
// two part: platform = NULL
// malloc and get platforms*
cl_uint num_platforms; //must be uint
cl_platform_id *platforms;
clGetPlatformIDs(5, NULL, &num_platforms);
printf("There are %d platforms \n", num_platforms);
platforms = (cl_platform_id*) malloc (num_platforms*sizeof(cl_platform_id));
clGetPlatformIDs(5, platforms, &num_platforms);
for(int i = 0; i < num_platforms; i++)
{
char name[40],vendor[40],version[40], profile[40],extensions[4096];
clGetPlatformInfo(platforms[i],CL_PLATFORM_NAME, sizeof(name), &name, NULL);
clGetPlatformInfo(platforms[i],CL_PLATFORM_VENDOR, sizeof(vendor), &vendor, NULL);
clGetPlatformInfo(platforms[i],CL_PLATFORM_VERSION, sizeof(vendor), &version, NULL);
clGetPlatformInfo(platforms[i],CL_PLATFORM_PROFILE, sizeof(vendor), &profile, NULL);
//clGetPlatformInfo(platforms[i],CL_PLATFORM_EXTENSIONS, sizeof(vendor), &extensions, NULL);
printf("Platform %d \n", i);
printf("Name %s \n", name);
printf("Vendor %s \n", vendor);
printf("Version %s \n", version);
printf("Profile %s \n", profile);
//printf("Extension %s \n", extensions);
printf("----------------------------------\n");
}
////////////////////////////////////////////////////////////////
//DEVICES QUERYING
////////////////////////////////////////////////////////////////
cl_device_id* devices;
cl_uint num_devices;
cl_device_fp_config flag ;
for(int i= 0; i< num_platforms; i++)
{
printf("Platform %d has:\n",i);
clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, 3, NULL, &num_devices);
devices = (cl_device_id*)malloc(num_devices*sizeof(cl_device_id));
clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, num_devices, devices, NULL);
char name[40];
for(int j=0; j < num_devices; j++)
{
int err= clGetDeviceInfo(devices[j],CL_DEVICE_NAME,sizeof(name),name,NULL);
if (err<0)
{
//printf("Error querying devices name\n");
}
else
{
printf("Device name %s \n", name);
}
err= clGetDeviceInfo(devices[j],CL_DEVICE_NAME,sizeof(flag),&flag,NULL);
if (flag & CL_FP_DENORM)
{
printf("This device support denormalized number \n");
}
}
printf("-----------------------------------\n");
}
///////////////////////////////////////////////////////
//CONTEXT QUERYING AND CREATING
////////////////////////////////////////////////////////
//NOTE clCreateContext returns cl_context instead of errors
//REF_COUNT if very important in the future
//create context for GPU
cl_context context;
cl_uint ref_count;
cl_int err;
char name[40];
context= clCreateContext(NULL,1,&devices[0], NULL,NULL,&err);
clGetContextInfo(context,CL_CONTEXT_REFERENCE_COUNT,sizeof(ref_count), &ref_count, NULL);
printf("Original reference count is %d \n",ref_count);
/*clRetainContext(context);
clGetContextInfo(context,CL_CONTEXT_REFERENCE_COUNT,sizeof(ref_count), &ref_count, NULL);
printf("Incremented reference count is %d \n",ref_count);
clReleaseContext(context);
clGetContextInfo(context,CL_CONTEXT_REFERENCE_COUNT,sizeof(ref_count), &ref_count, NULL);
printf("Decremented reference count is %d \n",ref_count);*/
////////////////////////////////////////////////////////
//Create programme
///////////////////////////////////////////////////////
size_t program_size;
err=0;
cl_program program;
char* program_buffer;
FILE* program_handle = fopen("kernel.cl","r");
//More recommendable than source code???
program_buffer = (char*)malloc(MAX_SOURCE_SIZE);
program_size = fread( program_buffer, 1, MAX_SOURCE_SIZE, program_handle);
fclose( program_handle );
program = clCreateProgramWithSource(context,1,(const char**) &program_buffer,
(size_t*)&program_size, &err);
////////////////////////////////////////////////////////
//Build Program
///////////////////////////////////////////////////////
//const char options[] = "-cl-finite-math-only -cl-no-signed-zeros";
char* program_log;
size_t log_size;
err= clBuildProgram(program, 1 , devices, NULL, NULL, NULL);
if(err < 0) //debug , printing log
{
clGetProgramBuildInfo(program, devices[0], CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size);
program_log = (char*) malloc(log_size+1);
program_log[log_size] = '\0';
clGetProgramBuildInfo(program,devices[0],CL_PROGRAM_BUILD_LOG,log_size,
program_log,NULL);
printf("%s\n",program_log);
free(program_log);
//exit(1);
}
///////////////////////////////////////////////////////////////////////////////////
//create kernel
///////////////////////////////////////////////////////////////////////////////////
cl_uint num_kernels;
cl_kernel kernel;
char kernel_name[40];
kernel = clCreateKernel(program,"add",&err);
if (err<0)
{
perror("could not found any kernels\n");
}
//kernels = (cl_kernel*)malloc(num_kernels*sizeof(cl_kernel));
//clCreateKernelsInProgram(program, num_kernels, kernels, NULL);
///FOR REFERNECE
//for(int i=0; i<num_kernels; i++)
//{
clGetKernelInfo(kernel,CL_KERNEL_FUNCTION_NAME,sizeof(kernel_name),kernel_name,NULL);
printf("Kernel function: %s \n",kernel_name);
//}
/////////////////////////////////////////////////////
//Create command queue
/////////////////////////////////////////////////////
cl_command_queue queue = clCreateCommandQueue(context, devices[0],CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE,&err);
if (err < 0)
{
printf("Couldn't create command queue \n");
exit(1);
}
clEnqueueTask(queue, kernel, 0, NULL, NULL);//only enqueue
//////////////////////////////////////////
unsigned int n= 1000;
int* h_a;
int* h_b;
int* h_c;
cl_mem d_a;
cl_mem d_b;
cl_mem d_c;
h_a = (int*) malloc(n*sizeof(int));
h_b = (int*) malloc(n*sizeof(int));
h_c = (int*) malloc(n*sizeof(int));
for(int i=0; i< n; i++)
{
h_a[i]= 1;//sinf(i)*sinf(i);
h_b[i]= 1;//cosf(i)*cosf(i);
}
d_a = clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR,sizeof(h_a),NULL,NULL);
d_b = clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR,sizeof(h_a),NULL,NULL);
d_c = clCreateBuffer(context, CL_MEM_WRITE_ONLY|CL_MEM_COPY_HOST_PTR,sizeof(h_a),NULL,NULL);
err = clEnqueueWriteBuffer(queue,d_a,CL_TRUE,0,sizeof(h_a),h_a,0, NULL, NULL);
err |= clEnqueueWriteBuffer(queue,d_b,CL_TRUE,0,sizeof(h_b),h_a,0, NULL, NULL);
//////set argument
err= clSetKernelArg(kernel,0,sizeof(cl_mem),&d_a);
err= clSetKernelArg(kernel,1,sizeof(cl_mem),&d_b);
err= clSetKernelArg(kernel,2,sizeof(cl_mem),&d_c);
err= clSetKernelArg(kernel,3,sizeof(unsigned int),&n);
///////////////
size_t globalsize, localsize;
localsize=64;
globalsize=ceil(n/(float)localsize)*localsize;
err= clEnqueueNDRangeKernel(queue,kernel,1, NULL,&globalsize,&localsize,0,NULL,NULL);
////////////////////////
clFinish(queue);
err=clEnqueueReadBuffer(queue, d_c,CL_TRUE, 0, sizeof(h_c), h_c, 0 , NULL, NULL);
for(int i = 0; i< n; i++)
{
printf(" h_c[%d] = %d \n", i, h_c[i]);
}
clReleaseMemObject(d_a);
clReleaseMemObject(d_b);
clReleaseMemObject(d_c);
clReleaseProgram(program);
clReleaseCommandQueue(queue);
clReleaseContext(context);
clReleaseKernel(kernel);
free(h_a);
free(h_b);
free(h_c);
getchar();
}
and here is my kernel.cl
__kernel void add(__global int * a, __global int *b, __global int* c, const unsigned n)
{
int id= get_global_id(0);
if (id<n)
c[id]= a[id] + b[id];
}
With this, I only received garbage values , for example h_c[i]= -842150451 for all i.
Please help me to fix it. Thanks!
This statement is not correct :
sizeof(h_a)
Should be something like :
n * sizeof(int)
Indeed h_a is just a pointer so sizeof(h_a) = sizeof(int) => you have the space for only one item.

Resources