decrypt/encrypt large data using RSA public key - c++

I wan encrypt large DATA using an RSA public key then decrypt it using the private key
So my encryption function is :
unsigned char* encryptFile::rsaEncrypt( RSA *pubKey, const unsigned char* msg, int msg_len, int *enc_len )
{
int rsa_size = RSA_size(pubKey);
int block_size = rsa_size - 12;
int blocks = msg_len/block_size;
int rest = msg_len % block_size;
unsigned char* enc = 0;
int curr_len = 0;
int i = 0;
if (0 == rest) {
enc = (unsigned char*)malloc(blocks*rsa_size + 1);
}
else {
enc = (unsigned char*)malloc((blocks+1)*rsa_size + 1);
}
for (i = 0; i < blocks; i++) {
if (0 > (curr_len = RSA_public_encrypt(block_size , msg + i*block_size, enc + i*rsa_size, pubKey, RSA_PKCS1_PADDING))) {
printf("ERROR: RSA_public_encrypt: %s\n", ERR_error_string(ERR_get_error(), NULL));
}
*enc_len += curr_len;
}
if (0 != rest) {
if (0 > (curr_len = RSA_public_encrypt(rest , msg + i*block_size, enc + i*rsa_size, pubKey, RSA_PKCS1_PADDING))) {
printf("ERROR: RSA_public_encrypt: %s\n", ERR_error_string(ERR_get_error(), NULL));
}
*enc_len += curr_len;
}
if( *enc_len == -1 )
printf("ERROR: RSA_public_encrypt: %s\n", ERR_error_string(ERR_get_error(), NULL));
cout << *enc_len << endl;
return enc;
}
And it's working fine !
Now when i want decrypt it i'm using this code
int rsa_size = RSA_size(privKey);
int msg_len = encBinLen;
int block_size = rsa_size;
int blocks = msg_len/block_size;
int rest = msg_len % block_size;
unsigned char* enc = 0;
int curr_len = 0;
enc_len = 0;
int i = 0;
if (0 == rest) {
enc = (unsigned char*)malloc(blocks*rsa_size + 1);
}
else {
enc = (unsigned char*)malloc((blocks+1)*rsa_size + 1);
}
for (i = 0; i < blocks; i++) {
if (0 > (curr_len = RSA_private_decrypt(block_size , msg + i*block_size, enc + i*rsa_size, privKey, RSA_PKCS1_PADDING))) {
printf("ERROR: RSA_public_encrypt: %s\n", ERR_error_string(ERR_get_error(), NULL));
}
enc_len += curr_len;
}
if (0 != rest) {
if (0 > (curr_len = RSA_private_decrypt(rest , msg + i*block_size, enc + i*rsa_size, privKey, RSA_PKCS1_PADDING))) {
printf("ERROR: RSA_public_encrypt: %s\n", ERR_error_string(ERR_get_error(), NULL));
}
enc_len += curr_len;
}
if( enc_len == -1 )
printf("ERROR: RSA_public_encrypt: %s\n", ERR_error_string(ERR_get_error(), NULL));
cout << enc;
Anyway when i run that some of the data got decrypted but i still see some weird chars as in seen in this picture
So i just want understand what i'm doing wrong ?

The solution is to use hybrid encryption !
Thnks to Artjom B. & zaph

I think you should use enc_len instead of i*rsa_size as shifter for output in RSA_private_decrypt(block_size , msg + i*block_size, enc + i*rsa_size, privKey, RSA_PKCS1_PADDING) call.

Related

C++ openssl - Generate RSA Keypair and read

I am trying to generate RSA keypair using openssl library and then read the same keys later. However, it fails. Sometimes it gives me this error:
error:0906D06C:PEM routines:PEM_read_bio:no start line
And sometimes, it gives me this error:
error:0906D06C:lib(9):func(109):reason(108)
What is the correct way to generate the keypair and later be able to read it ? Here is my code. If you run it, you will find that it correctly generates the RSA key pair but not able read them later.
#include <stdio.h>
#include <iostream>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <exception>
bool generate_key() {
size_t pri_len; // Length of private key
size_t pub_len; // Length of public key
char *pri_key; // Private key in PEM
char *pub_key; // Public key in PEM
int ret = 0;
RSA *r = NULL;
BIGNUM *bne = NULL;
BIO *bp_public = NULL, *bp_private = NULL;
int bits = 2048;
unsigned long e = RSA_F4;
EVP_PKEY *evp_pbkey = NULL;
EVP_PKEY *evp_pkey = NULL;
BIO *pbkeybio = NULL;
BIO *pkeybio = NULL;
// 1. generate rsa key
bne = BN_new();
ret = BN_set_word(bne, e);
if (ret != 1) {
goto free_all;
}
r = RSA_new();
ret = RSA_generate_key_ex(r, bits, bne, NULL);
if (ret != 1) {
goto free_all;
}
// 2. save public key
//bp_public = BIO_new_file("public.pem", "w+");
bp_public = BIO_new(BIO_s_mem());
ret = PEM_write_bio_RSAPublicKey(bp_public, r);
if (ret != 1) {
goto free_all;
}
// 3. save private key
//bp_private = BIO_new_file("private.pem", "w+");
bp_private = BIO_new(BIO_s_mem());
ret = PEM_write_bio_RSAPrivateKey(bp_private, r, NULL, NULL, 0, NULL, NULL);
//4. Get the keys are PEM formatted strings
pri_len = BIO_pending(bp_private);
pub_len = BIO_pending(bp_public);
pri_key = (char*) malloc(pri_len + 1);
pub_key = (char*) malloc(pub_len + 1);
BIO_read(bp_private, pri_key, pri_len);
BIO_read(bp_public, pub_key, pub_len);
pri_key[pri_len] = '\0';
pub_key[pub_len] = '\0';
printf("\n%s\n%s\n", pri_key, pub_key);
//verify if you are able to re-construct the keys
pbkeybio = BIO_new_mem_buf((void*) pub_key, -1);
if (pbkeybio == NULL) {
return -1;
}
evp_pbkey = PEM_read_bio_PUBKEY(pbkeybio, &evp_pbkey, NULL, NULL);
if (evp_pbkey == NULL) {
char buffer[120];
ERR_error_string(ERR_get_error(), buffer);
printf("Error reading public key:%s\n", buffer);
}
pkeybio = BIO_new_mem_buf((void*) pri_key, -1);
if (pkeybio == NULL) {
return -1;
}
evp_pkey = PEM_read_bio_PrivateKey(pkeybio, &evp_pkey, NULL, NULL);
if (evp_pbkey == NULL) {
char buffer[120];
ERR_error_string(ERR_get_error(), buffer);
printf("Error reading private key:%s\n", buffer);
}
BIO_free(pbkeybio);
BIO_free(pkeybio);
// 4. free
free_all:
BIO_free_all(bp_public);
BIO_free_all(bp_private);
RSA_free(r);
BN_free(bne);
return (ret == 1);
}
int main(int argc, char* argv[]) {
generate_key();
return 0;
}
Looks good to me. Except on reloading; I would have used PEM_read_bio_RSAPublicKey in stead of PEM_read_bio_PUBKEY.
I am not sure it is the best way to do it though.
--- /tmp/stack_openssl.cpp.back 2018-05-25 12:53:12.366488025 +0000
+++ /tmp/stack_openssl.cpp 2018-05-25 13:57:20.614066828 +0000
## -18,6 +18,8 ##
int bits = 2048;
unsigned long e = RSA_F4;
+ RSA *pb_rsa = NULL;
+ RSA *p_rsa = NULL;
EVP_PKEY *evp_pbkey = NULL;
EVP_PKEY *evp_pkey = NULL;
## -66,27 +68,32 ##
printf("\n%s\n%s\n", pri_key, pub_key);
//verify if you are able to re-construct the keys
- pbkeybio = BIO_new_mem_buf((void*) pub_key, -1);
+ pbkeybio = BIO_new_mem_buf((void*) pub_key, pub_len);
if (pbkeybio == NULL) {
return -1;
}
- evp_pbkey = PEM_read_bio_PUBKEY(pbkeybio, &evp_pbkey, NULL, NULL);
- if (evp_pbkey == NULL) {
+ pb_rsa = PEM_read_bio_RSAPublicKey(pbkeybio, &pb_rsa, NULL, NULL);
+ if (pb_rsa == NULL) {
char buffer[120];
ERR_error_string(ERR_get_error(), buffer);
printf("Error reading public key:%s\n", buffer);
}
+ evp_pbkey = EVP_PKEY_new();
+ EVP_PKEY_assign_RSA(evp_pbkey, pb_rsa);
- pkeybio = BIO_new_mem_buf((void*) pri_key, -1);
+ pkeybio = BIO_new_mem_buf((void*) pri_key, pri_len);
if (pkeybio == NULL) {
return -1;
}
- evp_pkey = PEM_read_bio_PrivateKey(pkeybio, &evp_pkey, NULL, NULL);
- if (evp_pbkey == NULL) {
+ p_rsa = PEM_read_bio_RSAPrivateKey(pkeybio, &p_rsa, NULL, NULL);
+ if (p_rsa == NULL) {
char buffer[120];
ERR_error_string(ERR_get_error(), buffer);
printf("Error reading private key:%s\n", buffer);
}
+ evp_pkey = EVP_PKEY_new();
+ EVP_PKEY_assign_RSA(evp_pkey, p_rsa);
BIO_free(pbkeybio);
BIO_free(pkeybio);

How to decompress a .zip file into folder using zlib.h library?

I have a .zip file to unzip which contain multiple sub-folders. I am using zlib.h library function to unzip the .zip file.
#include<stdio.h>
#include<zlib.h>
#define MAX_MOI_PATH 200
#define READ_BLOCK_SIZE 1024*16
BOOL DCompressFile(char *SourceFILENAME, char *DestinationFILENAME)
{
char buffer[READ_BLOCK_SIZE];
unsigned long dwBytesRead;
unsigned long numberOfBytesWritten;
Bool status = false;
char cFilename[MAX_MOI_PATH];
int pathIndex=0;
char FileMode[4] = "w";
gzFile * FileFd = (gzFile *)gzopen (SourceFILENAME, "rb");
if (FileFd)
{
FILE* handle = fopen(DestinationFILENAME, "wb");
if(handle != NULL)
{
status = true;
while (status)
{
dwBytesRead = gzread(FileFd, buffer, READ_BLOCK_SIZE-1);
buffer[dwBytesRead] = '\0';
if (dwBytesRead)
{
status = fwrite(buffer, 1 , sizeof(buffer) , handle );
if(!status)
status = false;
else if (dwBytesRead < READ_BLOCK_SIZE)
{
break;
status = false;
}
}
}
fclose(handle);
}
gzclose (FileFd);
}
return status;
}
int main()
{
DCompressFile("/home/vivek/zlib_test/1.zip","/home/vivek/zlib_test/1");
return 0;
}
problem with this source code is, it is creating again a zip file "1.zip" with same content, not decompressing the .zip file to folder.
please help what going wrong with this?
gzip is not zip. zip is not gzip. Completely different things. You need to find a library or class that handles zip files. zlib doesn't do this by itself.
I complete this task using libarchive
static int
copy_data(struct archive *ar, struct archive *aw)
{
int r;
const void *buff;
size_t size;
#if ARCHIVE_VERSION_NUMBER >= 3000000
int64_t offset;
#else
off_t offset;
#endif
for (;;) {
r = archive_read_data_block(ar, &buff, &size, &offset);
if (r == ARCHIVE_EOF)
return (ARCHIVE_OK);
if (r != ARCHIVE_OK)
return (r);
r = archive_write_data_block(aw, buff, size, offset);
if (r != ARCHIVE_OK) {
return (r);
}
}
}
static int
extract(const char *filename)
{
struct archive *a;
struct archive *ext;
struct archive_entry *entry;
int flags;
int r;
//Select which attributes we want to restore.
flags = ARCHIVE_EXTRACT_TIME;
flags |= ARCHIVE_EXTRACT_PERM;
flags |= ARCHIVE_EXTRACT_ACL;
flags |= ARCHIVE_EXTRACT_FFLAGS;
a = archive_read_new();
archive_read_support_filter_all(a);
archive_read_support_format_all(a);
ext = archive_write_disk_new();
archive_write_disk_set_options(ext, flags);
archive_write_disk_set_standard_lookup(ext);
if ((r = archive_read_open_filename(a, filename, 16384)))
{
printf("File name %s\n",filename);
return 1;
}
for (;;) {
r = archive_read_next_header(a, &entry);
printf("%s \n",archive_entry_pathname(entry));
if (r == ARCHIVE_EOF)
break;
if (r < ARCHIVE_OK)
{
fprintf(stderr, "%s\n", archive_error_string(a));
printf("Error1 : %s\n",archive_error_string(a));
if (r < ARCHIVE_WARN)
return 1;
}
r = archive_write_header(ext, entry);
if (r < ARCHIVE_OK){
fprintf(stderr, "%s\n", archive_error_string(ext));
printf("Error2 : %s\n",archive_error_string(ext));
}
else if (archive_entry_size(entry) > 0) {
r = copy_data(a, ext);
if (r < ARCHIVE_OK){
fprintf(stderr, "%s\n", archive_error_string(ext));
printf("Error3 : %s\n",archive_error_string(ext));
}
if (r < ARCHIVE_WARN)
return 1;
}
r = archive_write_finish_entry(ext);
if (r < ARCHIVE_OK){
fprintf(stderr, "%s\n", archive_error_string(ext));
printf("Error4 : %s\n",archive_error_string(ext));
}
if (r < ARCHIVE_WARN)
return 1;
}
archive_read_close(a);
archive_read_free(a);
archive_write_close(ext);
archive_write_free(ext);
return 0;
}
int main()
{
extract("/home/sanjay/zlib_test/FileDownload.zip");
return 0;
}

Fetch LAN ip addresses does not work

The codes are as follows. I want to enumerate all the ips. Part of the codes are used to my GUI, i am sure that the error has no relevance with them.
void udpchat1::getNameAndIp() {
struct hostent *host;
struct in_addr *ptr;
DWORD dwScope = RESOURCE_CONTEXT;
NETRESOURCE *NetResource = NULL;
HANDLE hEnum;
WNetOpenEnum(dwScope, NULL, NULL, NULL, &hEnum);
WSADATA wsaData;
WSAStartup(MAKEWORD(1, 1), &wsaData);
ui.IpListWidget->clear();
names.clear();
ui.chatIpLabel->setText("1111111111111");
sendAble = false;
// flag = false;
if (hEnum)
{
DWORD Count = 0xFFFFFFFF;
DWORD BufferSize = 10240;
LPVOID Buffer = new char[10240];
WNetEnumResource(hEnum, &Count, Buffer, &BufferSize);
NetResource = (NETRESOURCE*)Buffer;
char szHostName[200];
for (unsigned int i = 0; i < BufferSize / sizeof(NETRESOURCE); i++, NetResource++)
{
if (NetResource->dwUsage == RESOURCEUSAGE_CONTAINER && NetResource->dwType == RESOURCETYPE_ANY)
{
if (NetResource->lpRemoteName)
{
CString strFullName = NetResource->lpRemoteName;
if (0 == strFullName.Left(2).Compare(_T("\\\\")))
strFullName = strFullName.Right(strFullName.GetLength() - 2);
gethostname(szHostName, strlen(szHostName));
USES_CONVERSION;
char *pchar = T2A(strFullName);
host = gethostbyname(pchar);
if (host == NULL) continue;
ptr = (struct in_addr *) host->h_addr_list[0];
std::string str = "";
for (int n = 0; n < 4; n++)
{
CString addr;
if (n > 0)
{
str += ".";
}
int value = (unsigned int)((unsigned char*)host->h_addr_list[0])[n];
char p[20];
sprintf(p, "%d", value);
str.append(p);
}
names.insert(std::pair<std::string, std::string>(host->h_name, str));
ui.IpListWidget->addItem(QString::fromStdString(host->h_name));
//std::cout << "IP:" << str << " Name:" << host->h_name << std::endl;
}
}
}
delete Buffer;
WNetCloseEnum(hEnum);
}
WSACleanup();
}
I used debugging, and i found the program can not get in to this if statement.
if (NetResource->lpRemoteName)
Here is a screenshot of the debug inspector.

mysql udf respond is random

I call the function AES_Dec with the same Parameters. In most of the cases it returns the correct respond. But with a randomness of around 15% the respond is different.
char* AES_Dec(UDF_INIT* initid, UDF_ARGS* args, char* result, unsigned long* length, char* is_null, char* error)
{
//initialize variables
//initialize key
char *keyPlain = args->args[1];
int keylength = (static_cast<int>(args->lengths[1])) / 2;
uint16_t *key = new uint16_t;
hex2bin(keyPlain, reinterpret_cast<unsigned char*>(key));
//output
char *output = new char;
bin2hex(key , keylength, output);
*length = keylength* 2;
return output;
}
void hex2bin(const char* src, unsigned char* target)
{
while (*src && src[1])
{
*(target++) = char2int(*src) * 16 + char2int(src[1]);
src += 2;
}
}
int char2int(char input)
{
if (input >= '0' && input <= '9')
return input - '0';
if (input >= 'A' && input <= 'F')
return input - 'A' + 10;
if (input >= 'a' && input <= 'f')
return input - 'a' + 10;
return 0;
}
void bin2hex(unsigned short* pv, size_t len, char *output)
{
const unsigned char * buf = reinterpret_cast<const unsigned char*>(pv);
static const char* hex_lookup = "0123456789ABCDEF";
char *p = output;
for (int i = 0; i < len; i++) {
*p++ = hex_lookup[buf[i] >> 4];
*p++ = hex_lookup[buf[i] & 0x0F];
}
*p = '\0';
}
I call this function with the following parameters:
SELECT AES_Dec('2C4E907536FBB3C9FADD4CFBD45950EF03517AA5F7F402DA9E3ABD03FC6E0068EF39F3DFC26A92B871E8D8CE521EAF6C', 'B99DD1D646CDBC8505419D069B5C0209', '1')
The correct respond which is returned most of the time is:
B99DD1D646CDBC8505419D069B5C0209
And the respond which comes randomly is
B2323332333333323333333333333332
There are only these two responses. And I have no idea why the random respond appears. In a console application it all works fine without any problems. So the code should work.
Have anyone a solution?
Thank you.
Edit: the full quellcode:
#include "Header.h"
#ifdef HAVE_DLOPEN
my_bool AES_Dec_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
if (args->arg_count != 3) {
return 1;
}
else if (args->arg_type[0] != STRING_RESULT ||
args->arg_type[1] != STRING_RESULT ||
args->arg_type[2] != STRING_RESULT) {
return 1;
}
return 0;
}
void AES_Dec_clear(UDF_INIT *initid, char *is_null, char *message) {
}
void AES_Dec_add(UDF_INIT *initid, UDF_ARGS *args,
char *is_null, char *message) {
}
char* AES_Dec(UDF_INIT* initid, UDF_ARGS* args, char* result, unsigned long* length, char* is_null, char* error)
{
//initialize variables
//initialize modus
char* modChar = args->args[2];
int mod;
if (modChar[0] == '1')
mod = 1;
else
mod = 0;
//initialize key
char *keyPlain = args->args[1];
int keylength = (static_cast<int>(args->lengths[1])) / 2;
uint16_t *key = new uint16_t;
hex2bin(keyPlain, reinterpret_cast<unsigned char*>(key));
//initialize value
const char *plain = args->args[0];
int plainLength = 0;
if (mod == 0)
plainLength = args->lengths[0] / 2;
else
plainLength = args->lengths[0] / 2 - 16;
uint16_t *contentWithIv = new uint16_t;
uint16_t *iv = new uint16_t;
hex2bin(plain, (unsigned char*)contentWithIv);
if (mod == 1) {
for (int i = 0; i < 8; i++) {
iv[i] = *contentWithIv;
contentWithIv++;
}
}
else
iv == NULL;
uint16_t *plaintext = contentWithIv;
// Buffer for the decrypted text
uint16_t *decryptedtext = new uint16_t;
int decryptedtext_len, ciphertext_len;
// Initialise the library
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
// Encrypt the plaintext
decryptedtext_len = decrypt((unsigned char*)plaintext, plainLength, (unsigned char*)key, (unsigned char*)iv, (unsigned char*)decryptedtext, keylength * 8, mod);
// Add a NULL terminator. We are expecting printable text
decryptedtext[decryptedtext_len] = '\0';
// Clean up
EVP_cleanup();
ERR_free_strings();
char *finalDec = (char*)malloc(decryptedtext_len * 2);
bin2hex(decryptedtext, decryptedtext_len, finalDec);
*length = decryptedtext_len * 2;
return finalDec;
}
void AES_Dec_deinit(UDF_INIT *initid) {
free(initid->ptr);
}
void handleErrors(void) {
ERR_print_errors_fp(stderr);
abort();
}
int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext, int keylength, int mod)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
// Create and initialise the context
if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
// Initialise the decryption operation.
if (mod == 0) {
if (keylength == 128)
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, NULL))
handleErrors();
if (keylength == 192)
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_192_ecb(), NULL, key, NULL))
handleErrors();
if (keylength == 256)
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, NULL))
handleErrors();
}
else if (mod == 1) {
if (keylength == 128)
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
handleErrors();
if (keylength == 192)
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_192_cbc(), NULL, key, iv))
handleErrors();
if (keylength == 256)
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();
}
else
handleErrors();
// Provide the message to be decrypted, and obtain the plaintext output.
if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleErrors();
plaintext_len = len;
// Finalise the decryption.
if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
plaintext_len += len;
// Clean up
EVP_CIPHER_CTX_free(ctx);
return plaintext_len;
}
void hex2bin(const char* src, unsigned char* target)
{
while (*src && src[1])
{
*(target++) = char2int(*src) * 16 + char2int(src[1]);
src += 2;
}
}
int char2int(char input)
{
if (input >= '0' && input <= '9')
return input - '0';
if (input >= 'A' && input <= 'F')
return input - 'A' + 10;
if (input >= 'a' && input <= 'f')
return input - 'a' + 10;
return 0;
}
void bin2hex(unsigned short* pv, size_t len, char *output)
{
const unsigned char * buf = reinterpret_cast<const unsigned char*>(pv);
static const char* hex_lookup = "0123456789ABCDEF";
char *p = output;
for (int i = 0; i < len; i++) {
*p++ = hex_lookup[buf[i] >> 4];
*p++ = hex_lookup[buf[i] & 0x0F];
}
*p = '\0';
}
#endif /* HAVE_DLOPEN */

Change Mac address by adapter description

I'm using the excellent tool provided by Nate True # http://devices.natetrue.com/macshift/
It changes the Mac address by the adapter name. This is the source code:
const int versionMajor = 1;
const int versionMinor = 1;
#include <windows.h>
#include <objbase.h>
#include <netcon.h>
#include <stdio.h>
#include "validmacs.h"
void SetMAC(char * AdapterName, char * NewMAC) {
HKEY hListKey = NULL;
HKEY hKey = NULL;
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}",
0, KEY_READ, &hListKey);
if (!hListKey) {
printf("Failed to open adapter list key\n");
return;
}
FILETIME writtenTime;
char keyNameBuf[512], keyNameBuf2[512];
DWORD keyNameBufSiz = 512;
DWORD crap;
int i = 0;
bool found = false;
while (RegEnumKeyEx(hListKey, i++, keyNameBuf, &keyNameBufSiz, 0, NULL, NULL, &writtenTime)
== ERROR_SUCCESS) {
_snprintf(keyNameBuf2, 512, "%s\\Connection", keyNameBuf);
hKey = NULL;
RegOpenKeyEx(hListKey, keyNameBuf2, 0, KEY_READ, &hKey);
if (hKey) {
keyNameBufSiz = 512;
if (RegQueryValueEx(hKey, "Name", 0, &crap, (LPBYTE)keyNameBuf2, &keyNameBufSiz)
== ERROR_SUCCESS && strcmp(keyNameBuf2, AdapterName) == 0) {
printf("Adapter ID is %s\n", keyNameBuf);
found = true;
break;
}
RegCloseKey(hKey);
}
keyNameBufSiz = 512;
}
RegCloseKey(hListKey);
if (!found) {
printf("Could not find adapter name '%s'.\nPlease make sure this is the name you gave it in Network Connections.\n", AdapterName);
return;
}
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}",
0, KEY_READ, &hListKey);
if (!hListKey) {
printf("Failed to open adapter list key in Phase 2\n");
return;
}
i = 0;
char buf[512];
while (RegEnumKeyEx(hListKey, i++, keyNameBuf2, &keyNameBufSiz, 0, NULL, NULL, &writtenTime)
== ERROR_SUCCESS) {
hKey = NULL;
RegOpenKeyEx(hListKey, keyNameBuf2, 0, KEY_READ | KEY_SET_VALUE, &hKey);
if (hKey) {
keyNameBufSiz = 512;
if ((RegQueryValueEx(hKey, "NetCfgInstanceId", 0, &crap, (LPBYTE)buf, &keyNameBufSiz)
== ERROR_SUCCESS) && (strcmp(buf, keyNameBuf) == 0)) {
RegSetValueEx(hKey, "NetworkAddress", 0, REG_SZ, (LPBYTE)NewMAC, strlen(NewMAC) + 1);
//printf("Updating adapter index %s (%s=%s)\n", keyNameBuf2, buf, keyNameBuf);
//break;
}
RegCloseKey(hKey);
}
keyNameBufSiz = 512;
}
RegCloseKey(hListKey);
}
void ResetAdapter(char * AdapterName) {
struct _GUID guid = {0xBA126AD1,0x2166,0x11D1,0};
memcpy(guid.Data4, "\xB1\xD0\x00\x80\x5F\xC1\x27\x0E", 8);
unsigned short * buf = new unsigned short[strlen(AdapterName)+1];
void (__stdcall *NcFreeNetConProperties) (NETCON_PROPERTIES *);
HMODULE NetShell_Dll = LoadLibrary("Netshell.dll");
if (!NetShell_Dll) {
printf("Couldn't load Netshell.dll\n");
return;
}
NcFreeNetConProperties = (void (__stdcall *)(struct tagNETCON_PROPERTIES *))GetProcAddress(NetShell_Dll, "NcFreeNetconProperties");
if (!NcFreeNetConProperties) {
printf("Couldn't load required DLL function\n");
return;
}
for (unsigned int i = 0; i <= strlen(AdapterName); i++) {
buf[i] = AdapterName[i];
}
CoInitialize(0);
INetConnectionManager * pNCM = NULL;
HRESULT hr = ::CoCreateInstance(guid,
NULL,
CLSCTX_ALL,
__uuidof(INetConnectionManager),
(void**)&pNCM);
if (!pNCM)
printf("Failed to instantiate required object\n");
else {
IEnumNetConnection * pENC;
pNCM->EnumConnections(NCME_DEFAULT, &pENC);
if (!pENC) {
printf("Could not enumerate Network Connections\n");
}
else {
INetConnection * pNC;
ULONG fetched;
NETCON_PROPERTIES * pNCP;
do {
pENC->Next(1, &pNC, &fetched);
if (fetched && pNC) {
pNC->GetProperties(&pNCP);
if (pNCP) {
if (wcscmp(pNCP->pszwName, buf) == 0) {
pNC->Disconnect();
pNC->Connect();
}
NcFreeNetConProperties(pNCP);
}
}
} while (fetched);
pENC->Release();
}
pNCM->Release();
}
FreeLibrary(NetShell_Dll);
CoUninitialize ();
}
bool IsValidMAC(char * str) {
if (strlen(str) != 12) return false;
for (int i = 0; i < 12; i++) {
if ((str[i] < '0' || str[i] > '9')
&& (str[i] < 'a' || str[i] > 'f')
&& (str[i] < 'A' || str[i] > 'F')) {
return false;
}
}
return true;
}
void ShowHelp() {
printf("Usage: macshift [options] [mac-address]\n\n");
printf("Options:\n");
printf("\t-i [adapter-name] The adapter name from Network Connections.\n");
printf("\t-r Uses a random MAC address. This is the default.\n");
printf("\t-d Restores the original MAC address.\n");
printf("\t--help Shows this screen.\n\n");
printf("Macshift uses special undocumented functions in the Windows COM Interface that\n");
printf(" allow you to change an adapter's MAC address without needing to restart.\n");
printf("When you change a MAC address, all your connections are closed automatically\n");
printf(" and your adapter is reset.\n");
}
//Generates a random MAC that is actually plausible
void RandomizeMAC(char * newmac) {
_snprintf(newmac, 6, "%06X", rand() % numMacs);
for (int i = 3; i < 6; i++) {
_snprintf(&newmac[i*2], 2, "%02X", rand() & 0xFF);
}
newmac[12] = 0;
}
int main(int argc, char * * argv) {
printf("Macshift v%i.%i, MAC Changing Utility by Nathan True, macshift#natetrue.com\n\n", versionMajor, versionMinor);
//Parse commandline arguments
char * adapter = "Wireless";
char newmac[13];
int i;
if (argc == 1) {
ShowHelp();
return 0;
}
//Start out with a random MAC
srand(GetTickCount());
RandomizeMAC(newmac);
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case '-': //Extended argument
if (strcmp(argv[i]+2, "help") == 0) {
ShowHelp();
return 0;
}
break;
case 'r': //Random setting, this is the default
break;
case 'i': //Adapter name follows
if (argc > i + 1) adapter = argv[++i];
break;
case 'd': //Reset the MAC address
newmac[0] = 0;
}
}
else {
if (IsValidMAC(argv[i])) strncpy(newmac, argv[i], 13);
else printf("MAC String %s is not valid. MAC addresses must m/^[0-9a-fA-F]{12}$/.\n", argv[i]);
}
}
printf("Setting MAC on adapter '%s' to %s...\n", adapter, newmac[0] ? newmac : "original MAC");
SetMAC(adapter, newmac);
printf("Resetting adapter...\n");
fflush(stdout);
ResetAdapter(adapter);
printf("Done\n");
return 0;
}
I would like to change the Mac address by the description of an adapter, in addition to the name. So I need to modify this code so that if a matching name is not found, it falls back to changing the mac based on the description.
This is an example adapter:
name: Local Area Connection
description: Marvell Yukon 88E8055 PCI-E Gigabit Ethernet Controller
Unfortunately, being a Java developer I have limited experience with C++, so any help would be greatly appreciated.
Here's a C sample of GetAdaptersInfo, it prints out each adapters name and description (you can easily adapt it for your code by calling SetMAC on a match):
VOID EnumerateNetworkAdapters(VOID)
{
ULONG len = 0;
if (ERROR_BUFFER_OVERFLOW == GetAdaptersInfo(NULL, &len))
{
IP_ADAPTER_INFO *ipai;
ipai = malloc(len);
if (NO_ERROR == GetAdaptersInfo(ipai, &len))
{
IP_ADAPTER_INFO *p = ipai;
do
{
printf("name=%s description=%s\n", p->AdapterName, p->Description);
}
while (p = p->Next);
}
free(ipai);
}
}
Link against "Iphlpapi.lib".
Use GetAdaptersAddresses to get the adapter name(PIP_ADAPTER_ADDRESSES::FriendlyName) by comparing the description(PIP_ADAPTER_ADDRESSES::Description) before the call to SetMAC(). Example can be found in above MSDN link.