Using MySQL SQL convert MD5 into JAVA MD5 - sql

There are great posts on how to use JAVA to create a MYSQL MD5 hash, however is it possible to go the other way - use SQL to produce what java does ?
in SQL:
Select MD5('secret') = 5ebe2294ecd0e0f08eab7690d2a6ee69
in Java, the MD5 algo yields: 94-6634-108-20-48-32-16-114-85118-112-46-90-18105
First off I can see the Java one is a decimal representation, so pairing off the SQL output and converting to DECIMAL gives: 9419034148236208224240142171118144210166238105
The only part that's the same is the Front 2 and last 4.
Anyone have ideas on how to use SQL to generate what Java would produce?

I don't have this fully worked out, but hopefully, these hints will help:
In Java, if you take the direct result of the md.digest() call, you have a byte array.
Instead of converting that to a String representation, just output the bytes as Integers.
You'll see that they are:
94
-66
34
-108
-20
-48
-32
-16
-114
-85
118
-112
-46
-90
-18
105
So, the dashes in the resulting string conversion aren't separators, they are arithmetic signs.
The java hash is a simple concatenation of the byte values as (signed) ints.
When you Select MD5('secret'), you getting a string of 32 hex digits.
I verified that if in Java, you convert each byte to it's hex representation, and concatenate them, you get the same string that MySQL returns.
So, it seems to me that what you would need to do in MySQL is to iterate the result of Hex(), one hex char at a time (perhaps using SUBSTRING()), convert each to decimal, and concatenate them.
Edit - looks like you are almost doing it correctly, but you need to convert each pair of hex digits to Byte instead of int, so for example, '0xbe' is -66, not 190
Edit #2 - I was intrigued by how relatively difficult this is to do in MySQL, so I persisted (joke intended). The following stored function seems to do the job:
drop function if exists java_md5;
delimiter |
create function java_md5(secret VARCHAR(255))
RETURNS VARCHAR(255)
DETERMINISTIC
BEGIN
DECLARE result varchar(255);
DECLARE md5String char(255);
DECLARE pair char(2);
DECLARE pairInt int;
DECLARE idx int;
set md5String = MD5(secret);
set result = '';
set idx = 1;
WHILE(idx < 32) DO
set pair = substring(md5String, idx, 2);
set pairInt = ascii(unhex(pair));
set pairInt = if(pairInt > 127, pairInt - 256, pairInt);
set result = concat(result, pairInt);
set idx = idx + 2;
END WHILE;
RETURN result;
END|
delimiter ;
select java_md5('secret');

Related

Cast a hexadecimal string to an array of bigint in hive

I have a column that contains a length 16 hexademical string. I would like to convert it to a bigint. Is there any way to accomplish that? The usual approach returns null since the input string could represent a number > 2^63-1.
select
cast(conv(hash_col, 16, 10) as bigint) as p0,
conv(hash_col, 16, 10) as c0
from mytable limit 10
I have also tried using unhex(..),
cast(unhex(hash_col) as bigint) as p0 from mytable limit 10
but got the following error
No matching method for class org.apache.hadoop.hive.ql.udf.UDFToLong
with (binary). Possible choices: FUNC(bigint) FUNC(boolean)
FUNC(decimal(38,18)) FUNC(double) FUNC(float) FUNC(int) FUNC(smallint) FUNC(string) FUNC(timestamp) FUNC(tinyint) FUNC(void)
If I don't do the cast(.. as bigint) part, I get some undisplayable binary value for p0. It seems unhex is not exactly the inverse of hex in hive.
Your values are out of range for BigInt
Ref : https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types
Max range for BigInt is 9,223,372,036,854,775,807
Use decimal(20,0) instead.
select cast(conv('85A58F8B014692CA',16,10) as decimal(20,0))

TSQL - Create a GUID from a random text and then get back the original text value from that GUID

I'm curious, is there an efficient way to generate a GUID from a random string of text and then take that GUID and convert it back to the original random string of text without using any additional data/mapping? I looked around for ways to do it, but couldn't find anything substantial.
Take this variable as an example for the starting point. I want to know if I can generate a GUID from it and then destruct the GUID to get back the original #Text
DECLARE #Text CHAR(64) = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ;
It seems like you are leaning towards EncryptByPassPhrase() and DecryptByPassPhrase()
Example
declare #encrypt varbinary(200)
select #encrypt = EncryptByPassPhrase('MySecretKey', 'abc' )
select #encrypt
select convert(varchar(100),DecryptByPassPhrase('MySecretKey', #encrypt ))
In SQL Server a UNIQUEIDENTIFIER can be any 16bytes of data. Per:
a string constant in the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,
in which each x is a hexadecimal digit in the range 0-9 or a-f. For
example, 6F9619FF-8B86-D011-B42D-00C04FC964FF is a valid
uniqueidentifier value.
https://learn.microsoft.com/en-us/sql/t-sql/data-types/uniqueidentifier-transact-sql?view=sql-server-ver15
So any 16 character or less varchar can be round-tripped through a UNIQUEIDENTIFIER. Eg
declare #d varchar(16) = 'hello world'
declare #u uniqueidentifier = cast(cast(#d as varbinary(16)) as uniqueidentifier)
select cast(cast(#u as varbinary(16)) as varchar(16))
To add some general thoughts:
As you were told already, a GUID has a length of 16 bytes.
Assuming you can reduce your string to plain latin lower-case characters you have to deal with 26, together with numbers with 36 different values (not speaking of any dot, comma or question mark etc).
The count of bits reflects the number of possible values. One byte of 8 bit can represent 256 (2^8) different values. For 26 letters you'd need at least 5 bit (2^5=32), together with the numbers you'd have to go up to 6 bit (64 values). The 16-byte GUID represents 128 bits (16x8=128). You could divide this by 5 (~25) or by 6 (~21).
That means: Reduced to 26 plain latin characters you could (with quite some effort) encode up to 25 characters in the memory allocated by one GUID (by using chunks of 5 bits). Together with numbers you are limited to a length of 21.
If you want to deal with any VARCHAR value (which is extended ASCII), you can translate a string to binary and then to GUID and back easily (David Brown showed this in his answer), as long as you limit this to a length of 16 characters.
Otherwise you would need some kind of dictionary on both sides...

Output of cast function

I am working on the usage of the Cast function in SQL Server. If I use explicit value as written in the code. The output is 38 which is the correct value. But I would need to use field names instead of direct values(There is only value of Base, escalator here ; Base =1.15 and escalator=0.05. But when I use field names, the output is 37. The data type of Base and escalator fields is float. I also tried using round function inside cast, did not solve the issue. Could someone out here help me with this. My query below:
Select CAST((3.05-1.15)/0.05 AS INT) -- returns 38
Select ((3.05-1.15)/0.05) --returns 38
Select cast((3.05-base)/Escalator) as int) from table1 -- I am using field names here. Returns 37
What is likely happening here is that the base and Escalator columns are some kind of non exact floating point type. As a result, the following computation results a value which is slightly less than 38:
(3.05-base) / Escalator = 37.999995 (for example)
Then, when casting to integer, the entire decimal component is being truncated, leaving behind just 37.
One possible workaround to prevent this from happening would be to use NUMERIC or some other exact type for the base and Escalator columns.
You can use Decimal to get rid of the issue
DECLARE #Escalator DECIMAL(7, 5) = 0.05
Select ((3.05-1.15)/0.05) --returns 38
Select CAST(((3.05-1.15)/#Escalator) AS INT) -- returns 38
Demo on db<>fiddle
you can use ceiling or floor inbuilt function based on your requirement
DECLARE #Escalator float = 0.05
DECLARE #Base float = 1.66
Select ((3.05-1.66)/0.05) --returns 27.8
Select ceiling (((3.05-#Base)/#Escalator)) -- returns 28
Select floor (((3.05-#Base)/#Escalator)) -- returns 27

How to process bitand operation in Informix with column in hex string format

In table I have string column which contains a hex value. For example value '000000000000000a' means 10. Now I need to process bitand operation: bitand(tableName.hexColumn, ?). When I read the Informix specification of this function it needs 2 int. So my question is: what is the simpler way to process this operation?
PS: Probably there is no solution in Informix so I will have to create my own bitandhexstring function where input will be 2 string and hex form but I have no idea where to start.
There are a variety of issues to be dealt with:
Your hex string has 16 digits, so the values are presumably (in general) 64-bit quantities. That means you need to be sure that the BITAND function has a variant that handles BIGINT (or perhaps INT8 — I'm not going to mention INT8 again, but it is nominally an option when BIGINT is mentioned) data.
You need to convert your hex string to a BIGINT.
It is not clear whether you'll need to convert the result BIGINT back to a hex string.
Some testing with Informix 11.70.FC6 on Mac OS X 10.10.4 shows that BITAND is safe with 64-bit numbers. That's good news!
The HEX function, when passed a BIGINT, returns a CHAR(20) string that starts with 0x and contains a hex representation of the number, so that more or less addresses point 3. The residual issue is 'how to convert 16-byte strings of hex digits to a BIGINT value'. Nominally, a cast operation like:
CAST('0xde3962e8c68a8001' AS BIGINT)
should do the job (but see below). There may be a better way of doing it than a brute-force and ignorance stored procedure, but I'm not immediately sure what it is.
Caveat Lector.
While testing this, I tried two queries:
SELECT bi, HEX(bi) FROM Test_BigInt;
SELECT bi, HEX(bi), SUBSTR(HEX(bi), 3, 16) FROM Test_BigInt;
on a table Test_BigInt with a single column bi of type BIGINT (not null, as it happened, but that's not material).
The first query worked fine. The type of the HEX(bi) expression was CHAR(20) and the values were like
0 0x0000000000000000
6898532535585831936 0x5fbc82ca87117c00
-2300268458811555839 0xe013ce0628808001
The second query sort of worked for small values of bi (0, 1, 2), but generated an error -1215: Value exceeds limit of INTEGER precision when the values got large. The problem is not the SUBSTR function directly. This was testing with Informix 11.70.FC6 on Mac OS X 10.10.4 — tested on 2015-07-08. The following pair of queries worked as expected (which is my justification for claiming that the problem is not in the SUBSTR function per se).
SELECT bi, HEX(bi) AS hex_bi FROM Test_BigInt INTO TEMP t;
SELECT bi, hex_bi, SUBSTR(hex_bi, 3, 16) FROM t;
It seems to be an interaction problem when the result of HEX is used in a string operation context. I first got the problem when trying to concatenate an empty string to the result of HEX: HEX(bi) || ''. That turns out to be unnecessary given that the result of HEX is reported as CHAR(20), but also indicates SUBSTR is not directly at fault.
I also tried CAST to get the hex string converted to BIGINT:
SELECT CAST('0xde3962e8c68a8001' AS BIGINT) FROM dual;
BIGINT
-964001791
SELECT HEX(CAST('0xde3962e8c68a8001' AS BIGINT)) FROM dual;
CHAR(18)
0xffffffffc68a8001
Grrr! Something is mishandling the conversion. This is not new software (well over 2 years old), but the chances are that unless someone else has spotted the bug, it has not yet been fixed, even in the latest version.
I've reported this through back-channels to IBM/Informix.
Stored procedures to convert hex string to BIGINT
CREATE PROCEDURE hexval(c CHAR(1)) RETURNING INTEGER;
RETURN INSTR("0123456789abcdef", lower(c)) - 1;
END PROCEDURE;
CREATE PROCEDURE hexstr_to_bigint(ival VARCHAR(18)) RETURNING bigint;
DEFINE oval DECIMAL(20,0);
DEFINE i,j,len INTEGER;
LET ival = LOWER(ival);
IF (ival[1,2] = '0x') THEN LET ival = ival[3,18]; END IF;
LET len = LENGTH(ival);
LET oval = 0;
FOR i = 1 TO len
LET j = hexval(SUBSTR(ival, i, 1));
LET oval = oval * 16 + j;
END FOR;
IF (oval > 9223372036854775807) THEN
LET oval = oval - 18446744073709551616;
END IF;
RETURN oval;
END PROCEDURE;
Casual testing:
execute procedure hexstr_to_bigint('000A');
10
execute procedure hexstr_to_bigint('FFff');
65535
execute procedure hexstr_to_bigint('FFFFffffFFFFffff');
-1
execute procedure hexstr_to_bigint('0XFFFFffffFFFFffff');
-1
execute procedure hexstr_to_bigint('000000000000000A');
10
Those values are correct.

Convert Hex To unsigned long integer in SQL

I have value like this
DECLARE #hex VARCHAR(64) = '00E0'
and I need to convert this value to a double.
I have code in C language
double conver_str_to_temp(char *strTemp)
{
int iTemp;
double fTemp;
iTemp = strtoul(strTemp, 0, 16); //strTemp is the string get from the message.
if (iTemp & 0x8000) //This means this is a negative value
{
iTemp -= 0x10000;
}
fTemp = iTemp * 0.0625;
return fTemp;
}
Result for :'00E0' is 14.000000
Result for : 'FF6B' is -9.312500
But problem is I'm not good in T-SQL.
How can I convert this C code to T-SQL function for use in SQL Server ?
There's no function to convert a string containing a hexadecimal value to a number directly. But you can use intermediate conversion to varbinary, which could then be easily converted to an integer.
However, when converting to a varbinary, you will need to specify the correct format, so that the string is interpreted as a hexadecimal value (rather than a string of arbitrary digits and letters). This
CONVERT(varbinary, '00E0')
which in fact defaults to CONVERT(varbinary, '00E0', 0), will result in every character being converted individually, because that's what the 0 format specifier does. So, every '0' will be converted to 0x30 and 'E' to 0x45, which will ultimately give you 0x30304530 – most probably not the result you want.
In contrast, this
CONVERT(varbinary, '00E0', 2)
results in 0x00E0, because the 2 format specifier tells the function to interpret the string as a (non-prefixed) hexadecimal value.
Now that you've got the correct varbinary representation of the string, you can use either of the methods suggested by #armen to convert the value to an integer: like this
CONVERT(varbinary, '00E0', 2) * 1
or like this:
CONVERT(int, CONVERT(varbinary, '00E0', 2))
To explain the former method a little, it uses implicit conversion: since the other operand of multiplication, 1, is an int and int has higher precedence than varbinary, the varbinary operand is implicitly converted to int (which gives 224 in this particular case) before the multiplication can take place.
You can read more about conversion in the manual.
try this-:
DECLARE #hex VARCHAR(64) = '00E0'
SELECT CONVERT(VARBINARY, #hex) * 1
-- OR
SELECT CONVERT(INT, CONVERT(VARBINARY, #hex))
in TSQL, you need not employ a conversion function,
SQL Server will convert the HEX value into the integer intrinsically.
in your case you can do the below
declare #hex float
set #hex = 00E0
select #hex