objective-c implementation of mySQL encrypt() function - mysql

I have a mySQL database with hashed passwords that I cannot abandon. I need to duplicate the encrypt() function of mySQL so that I can be consistent in my hash creation for login in an iOS app I'm creating. (I'm using the first 2 characters of the password as the salt for the encrypt function)
Has anyone done this before? I tried to add the following category to NSString based on code I found elsewhere, but the resulting string isn't even close. (I have a base64 category on NSData and yes, I'm new to the CCCrypt call)
-(NSString*) encryptWithSalt:(NSString *)salt {
NSString *token = self;
const void *vplainText;
size_t plainTextBufferSize = [token length];
vplainText = (const void *) [token UTF8String];
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
bufferPtrSize = (plainTextBufferSize + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x0, bufferPtrSize);
uint8_t iv[kCCBlockSizeDES];
memset((void *) iv, 0x0, (size_t) sizeof(iv)); // zero out iv
const void *vkey = (const void *) [salt UTF8String];
ccStatus = CCCrypt(kCCEncrypt,
kCCAlgorithmDES,
kCCOptionPKCS7Padding | kCCModeCBC,
vkey,
kCCKeySizeDES,
iv,
vplainText,
plainTextBufferSize,
(void *)bufferPtr,
bufferPtrSize,
&movedBytes);
NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
NSString* hash;
if (ccStatus == kCCSuccess) {
hash = [myData base64EncodedString];
}
return hash;
}

The crypt() function cannot be emulated using CCCrypt, as the salt is used to alter the DES E-box. This makes the cipher in use no longer really DES.
However, it's still just the crypt() function. Call it directly:
- (NSString*) encryptWithSalt:(NSString *)salt {
return [NSString stringWithUTF8String:crypt([self UTF8String], [salt UTF8String])];
}
Incidentally, using the first two characters of the password as the salt is a gigantic security hole, as it narrows the password search space down to six characters (because the first two are given away by the salt).

Related

DotNet Interop -- is AllocHGlobal my only option

I inherited some old Interop code and wanted to update it for the newer guidance, as it uses StringBuilder.
https://learn.microsoft.com/en-us/dotnet/standard/native-interop/best-practices
I do not have access to the source code to the native method.
[DllImport(NativeLib, CharSet = CharSet.Ansi, ExactSpelling = true)]
static extern int native_func(double input, StringBuilder result);
public string Convert(double input)
{
var res = new StringBuilder();
if (native_func(input, res) == 0)
return res.ToString();
throw ...;
}
I was able to convert things to manually use AllocateHGlobal instead of StringBuilder.
[DllImport(NativeLib, CharSet = CharSet.Ansi, ExactSpelling = true)]
static extern int native_func(double input, IntPtr result);
public string Convert(input val)
{
var res = Marshal.AllocHGlobal(100);
// pretend we are calling Marshal.FreeHGlobal later...
if (native_func(input, res) == 0)
return Marshal.PtrToStringAnsi(res);
throw ...;
}
But that's not the new ref/span/etc hotness.
However, no matter what I seem to try for the result parameter, I either get just the first character, or a System.AccessViolationException.
I've tried MemoryMarshal.GetReference, I've tried pinning, I've tried ref-ing, I've tried out-ing; whenever I'm trying to use a managed buffer, it just doesnt' work.
Are there scenarios where the new interop just doesn't work? Is AllocHGlobal the best I can do?

Refresh MYSQL UDF

I am trying to use my own UDF (written in c++) as a mysql extension. I was able to install the function via
CREATE FUNCTION decrypt RETURNS STRING SONAME "libudf_func.so";
and use it. I could also drop the function via
DROP FUNCTION decrypt;
After that it would not be listed in the mysql.func table, so Im pretty sure it was successfully deleted.
Now I want to use an updated version of my function, and therefore reload it in mysql. However, mysql only reloads the old version of my file (which I completely removed from the computer). Even if I remove ALL files named "libudf_func.so" it will be reloaded.
I'm using mysql version 8.0.28 for macos12.0 on localhost.
How can I remove this cached version or force mysql to reload?
EDIT
All my steps, from loading the first version to my attempt to load the updated version:
I used: CREATE FUNCTION decrypt RETURNS STRING SONAME "libudf.so"; to initially create the function decrypt
I changed something in my udf.cpp file.
I used: DROP FUNCTION decrypt; to remove the function decrypt
I used CREATE FUNCTION decrypt RETURNS STRING SONAME "libudf.so"; as an attempt to reload/refresh the function decrypt (NO ERRORS)
the behaviors did not change (among other things I wanted to output a different error message, so that was pretty obviously the old behavior)
I renamed libudf.so to lubudf_func.so
I replicated this with the new name.
I deleted ALL files with the names libudf.so or lubudf_func.so from my machine
I could still execute CREATE FUNCTION decrypt RETURNS STRING SONAME "libudf.so"; without any errors
I tried to call CREATE FUNCTION decrypt RETURNS STRING SONAME "libudf_xyz.so"; (never existed), which failed. Error message: "Error Code: 1126. Can't open shared library 'libudf_xyz.so' (errno: 2 dlopen(/usr/local/opt/mysql/lib/plugin/libudf_xyz.so, 0x0002): tried: '/usr/local/opt/mysql/lib/plugin/libudf_xyz.so' (no such f)"
plugin_dir: /usr/local/opt/mysql/lib/plugin/
--->(this is where the .so file WAS located, but is not anymore)
How did I notice the old behavior was still present? The dead giveaway was that the function used the old error message ("Please use plaintext(int), iv(string), key(string)"), and not the new message ("Please use plaintext(string), iv(string), key(string)") after step no. 4
Also add the content of the plugins/ directory, which CREATE FUNCTION uses to load the function: I wrote the library in c++, then built it as a shared library. The c++ code would be as follows (but Im not sure this is relevant):
extern "C" {
bool decrypt_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
char *decrypt(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error);
void decrypt_deinit(UDF_INIT *initid);
}
bool decrypt_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
if (args->arg_count != 3 or
args->arg_type[0] != STRING_RESULT or
args->arg_type[1] != STRING_RESULT or
args->arg_type[2] != STRING_RESULT
) {
strcpy(message, "Usage: decrypt_poly(string ctext, string key, string iv)");
return 1;
}
if (args->lengths[2] != 48) {
strcpy(message, "Only 24-length IVs are allowed. Make sure IV is hexed.");
return 1;
}
initid->ptr = new char[args->lengths[0]];
initid->maybe_null = 1;
return 0;
}
char *decrypt(UDF_INIT *initid, UDF_ARGS *args,
char *result, unsigned long *length,
char *is_null, char *error) {
std::string dvalue;
if (NULL != args->args[0]) {
std::string value = std::string(args->args[0], args->lengths[0]);
std::string key = std::string(args->args[1], args->lengths[1]);
std::string iv = std::string(args->args[2], args->lengths[2]);
try {
dvalue = ((encryption::poly_based_encryption::decrypt(value, key, iv))));
}
catch (CryptoPP::Exception &e) {
std::cerr << e.what() << std::endl;
*error = 1;
}
} else {
dvalue = "";
*is_null = 1;
*error = 1;
return NULL;
}
strcpy(initid->ptr, dvalue.c_str());
*length = dvalue.length();
result = initid->ptr;
*is_null = 0;
*error = 0;
return result;
}
void decrypt_deinit(UDF_INIT *initid) {
if (initid->ptr)
delete[] initid->ptr;
}

Gettinig an INT at the end of the Serialized JSON

So I'm updating this as I've gotten JSON OUT however the JSON is followed by an INT
{"function":"timereport","values":545028}41
#include <ArduinoJson.h>
char owner[] = "";
const int capacity = JSON_OBJECT_SIZE(2);
DynamicJsonDocument doc(capacity);
void setup() {
Serial.begin(115200);
}
void loop() {
doc["function"]="timereport";
doc["values"]=millis();
Serial.println(serializeJson(doc, Serial));
delay(5000);
}
Second TRY:(Post Still has the INT at the end)
char json_string[256];
http.begin("http://192.168.1.103:2000/hydroapi"); //Specify destination for HTTP request
http.addHeader("Content-Type","application/json");
doc["function"]="timereport";
doc["values"]=millis();
serializeJson(doc, json_string);
int httpResponseCode = http.POST(json_string); //Send the actual POST request
http.end();
The call to serializeJson prints the json to Serial (as that's the stream your passing in) and returns the number of bytes printed, which you're then explicitly printing using Serial.println.
Remove the call to Serial.println to avoid printing the number of bytes, just call serializeJson(doc, Serial);

Sending JSON data (Twitter (Temboo)) from Processing to Arduino

I'm working on a student project and trying to send JSON data (based on the twitter hashtag '#tune') from Processing to Arduino, but the method 'myPort.write(status);' isn't usable with JSON, I've looked around online but not sure what command to use - Am I on the right track? Here's the code:
Processing:
import processing.serial.*; //Serial connection for Arduino
import java.lang.reflect.Method;
import com.temboo.core.*; // Temboo library
import com.temboo.Library.Twitter.Search.*; // Temboo Twitter search library
// Create a session using your Temboo account application details
TembooSession session = new TembooSession("MYUSERNAME", "MYTEMBOOAPPNAME", "MYTEMBOOCODE");
// Setup objects
Serial myPort; // Create object from Serial class
int portNo = 7; // Define portNo as int
int baudRate = 9600; // Define baudRate as int
void setup() {
// Run the Tweets Choreo function
runTweetsChoreo();
String portName = Serial.list()[portNo]; // Setup String for port ([7] is the port number for my machine)
myPort = new Serial(this, portName, baudRate); // Setting up serial port
}
void runTweetsChoreo() {
// Create the Choreo object using your Temboo session
Tweets tweetsChoreo = new Tweets(session);
// Set credential
tweetsChoreo.setCredential("ArduinoUkulele");
// Set inputs
// Run the Choreo and store the results
TweetsResultSet tweetsResults = tweetsChoreo.run();
// retrieve the results as JSON
JSONObject results = parseJSONObject(tweetsResults.getResponse());
// retrieve the statuses from the results
JSONArray statuses = results.getJSONArray("statuses");
// loop through the statuses
for (int i = 0; i < statuses.size(); i++){
JSONObject status = statuses.getJSONObject(i);
println(status.getString("text"));
println(" -- -- -- -- -- -- -- -- -- -- -- -- -- -- ");
myPort.write(status); // THIS IS THE CODE NOT WORKING WITH JSON
}
}
Arduino:
char val; // Data received from the serial port
int ledPin = 13; // Set the pin to digital I/O 13
void setup(){
pinMode(ledPin, OUTPUT); // Set pin as OUTPUT
Serial.begin(9600); // Start serial communication at 9600 bps
}
void loop(){
if (Serial.available()) { // If data is available to read,
val = Serial.read(); // read it and store it in val
Serial.println(val);
delay(10); // Wait 10 milliseconds for next reading
}
}
I'm sure I'm just looking for a certain command - once I've received the data I'm just looking to turn the LED on based on a new hashtag being receieved. Any help would be greatly appreciated!
Cheers
Arthur
write() method cannot take JSONObject as input, only byte[], String. But you already have everything you need: just use getString() method as you are doing it two lines above (using appropriate key string, which you should know from API that you are using on top of JSON):
myPort.write(status.getString("text"));

AES 256 bit key encryption with PBKDF2 in Win RT and WP8

I am trying to port a WP8 application to Win 8.1 store App. The app uses password based AES 256 for encryption. The confusion I am having is that I am able to decrypt the text from WP8, encrypted using 256 bit key, but only using a 32 bit key in Win RT.
Below is the Window Phone 8 code. Here note that Rfc2898DeriveBytes wants it in bytes, so the key used is 256 bits.
private static string Decrypt(string dataToDecrypt, string password, string salt)
{
AesManaged aes = null;
MemoryStream memoryStream = null;
try
{
//Generate a Key based on a Password and HMACSHA1 pseudo-random number generator
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt), 10000);
//Create AES algorithm
aes = new AesManaged();
aes.KeySize = aes.LegalKeySizes[0].MaxSize; // returns 256
aes.BlockSize = aes.LegalBlockSizes[0].MaxSize; // return 128
aes.Key = rfc2898.GetBytes(aes.KeySize);
aes.IV = rfc2898.GetBytes(aes.BlockSize);
//Create Memory and Crypto Streams
memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write);
//Decrypt Data
byte[] data = Convert.FromBase64String(dataToDecrypt);
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
//Return Decrypted String
byte[] decryptBytes = memoryStream.ToArray();
//Dispose
if (cryptoStream != null)
cryptoStream.Dispose();
//Retval
return Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
}
catch (Exception ex)
{
MasterData.CryptographyExceptionOccured = true;
Debug.WriteLine(ex.Message);
Debug.WriteLine(ex.StackTrace);
return "";
}
finally
{
if (memoryStream != null)
memoryStream.Dispose();
if (aes != null)
aes.Clear();
}
}
Below is the Win RT code (Win 8.1) Here note that the CryptographicEngine.DeriveKeyMaterial method requires the key size in bits. But I am able to decrypt the 256 bit encryption in WP8 using the below Win RT code, which seems to use 32 bits only. ( The password and salt used are same in WP8 / Win RT)
private static void GenerateKeyMaterial(string password, string salt, uint iterationCount, out IBuffer keyMaterial, out IBuffer iv)
{
// Setup KDF parameters for the desired salt and iteration count
IBuffer saltBuffer = CryptographicBuffer.ConvertStringToBinary(salt, BinaryStringEncoding.Utf8);
KeyDerivationParameters kdfParameters = KeyDerivationParameters.BuildForPbkdf2(saltBuffer, iterationCount);
// Get a KDF provider for PBKDF2, and store the source password in a Cryptographic Key
KeyDerivationAlgorithmProvider kdf = KeyDerivationAlgorithmProvider.OpenAlgorithm(KeyDerivationAlgorithmNames.Pbkdf2Sha256);
// KeyDerivationAlgorithmProvider kdf = KeyDerivationAlgorithmProvider.OpenAlgorithm(KeyDerivationAlgorithmNames.Pbkdf2Sha1); IBuffer passwordBuffer = CryptographicBuffer.ConvertStringToBinary(password, BinaryStringEncoding.Utf8);
CryptographicKey passwordSourceKey = kdf.CreateKey(passwordBuffer);
// Generate key material from the source password, salt, and iteration count. Only call DeriveKeyMaterial once,
// since calling it twice will generate the same data for the key and IV.
int keySize = 256 / 8;
int ivSize = 128 / 8;
uint totalDataNeeded = (uint)(keySize + ivSize);
IBuffer keyAndIv = CryptographicEngine.DeriveKeyMaterial(passwordSourceKey, kdfParameters, totalDataNeeded);
// Split the derived bytes into a seperate key and IV
byte[] keyMaterialBytes = keyAndIv.ToArray();
keyMaterial = WindowsRuntimeBuffer.Create(keyMaterialBytes, 0, keySize, keySize);
iv = WindowsRuntimeBuffer.Create(keyMaterialBytes, keySize, ivSize, ivSize);
}
So to use a 256 bit encryption in Win RT, what should be the key size in the above code? How is it possible to decrypt a 256 bit encrypted string using a 32 bit key. See the above WP8 and Win RT code.