Character generated from SHA-512 hash does not get saved to database - algorithm

I'm hashing a password using SHA512. I'm using Entity Framework Code-First for my ORM.
Hashing Algorithm
public static string CreateSHA512Hash(string pwd, string salt)
{
string saltAndPwd = String.Concat(pwd, salt);
var ae = new ASCIIEncoding();
byte[] hashValue, messageBytes = ae.GetBytes(saltAndPwd);
var sHhash = new SHA512Managed();
hashValue = sHhash.ComputeHash(messageBytes);
sHhash.Dispose();
return ae.GetString(hashValue);
}
Code for generating salt:
//Generate a cryptographic random number.
var rng = new RNGCryptoServiceProvider();
var buff = new byte[size];
rng.GetBytes(buff);
rng.Dispose();
// Return a Base64 string representation of the random number.
return Convert.ToBase64String(buff);
Problem:
For some reason, it seems the hash function would randomly generate some characters, which the ones after those are not saved to the database. In this case (I'm not sure if there are other characters that does this), but it is \0.
For eg. Password: testuser. Salt: uvq5i4CfMcOMjKPkwhhqxw==
Hash generated: ????j???7?o\0?dE??????:???s?x??u?',Vj?mNB??c???4H???vF\bd?T? (copied during dubug mode in visual studio).
But EF actually saves ????j???7?o to the database. If I try to use the text visualizer in debug mode, it cuts it off also. If you noticed, it gets cut off right at the \0. All I could find about it is that its a null character.
Question
How can I save this null character in the database using Entity Framework Code-First? If this can't be saved, how can I prevent the SHA512 from generating these characters for me?

I recommend encoding the hash with Base64 before saving. On the other hand, encoding the salt with Base64 before adding to the password sounds strange.

A SHA-256 hash does not generate characters, it generates bytes. If you want to have a character string, as opposed to a byte array, you need to convert the bytes into a character format. As #wRAR has suggested, Base64 is one common way to do it or else you could just use a hex string.

What you should probably do:
Return the array of bytes for the SHA512 hash not a string.
Use a BINARY(64) database column to hold your hash value.
Why your method doesn't work:
These ASCII strings are NULL terminated
NULL is as you said \0
SHA512 creates a byte array and any byte can be NULL
To answer your specific question:
wRAR above was saying.
return Convert.ToBase64String(hashValue);

Related

String is unexpectedly converted to hex

I tried to get some data from Firebird database. I have a field "UID", whose value is de6c50a94aee524d9d287a43158360f4 String(16).
When I get it with Ruby, I got:
"UID"=>"\xDElP\xA9J\xEERM\x9D(zC\x15\x83`\xF4"
Why didn't I get a string?
conn.query(:hash , 'SELECT FIRST 1 UID FROM cmd').first
The UID you receive is a binary array, which in ruby is represented as a packed string. To unpack it do the following:
"\xDElP\xA9J\xEERM\x9D(zC\x15\x83`\xF4".unpack('n*').map { |x| x.to_s(16) }.join
# => "de6c50a94aee524d9d287a43158360f4"
Your UID is a 128bit value. The hex string representation of UID can be built with unpack:
str = "%08x%04x%04x%04x%04x%08x" % UID.unpack("NnnnnN")
=> "de6c50a94aee524d9d287a43158360f4"
The reason for the specific formatting is this code is really for UUID's
str = "%08x-%04x-%04x-%04x-%04x%08x" % UID.unpack("NnnnnN")
=> "de6c50a9-4aee-524d-9d28-7a43158360f4"
As I commented, I guess the datatype of UID in your Firebird database is a CHAR(16) CHARACTER SET OCTETS, this is a binary datatype. Firebird (before Firebird 4) doesn't know the SQL types BINARY or VARBINARY, but fields with CHARACTER SET OCTETS are binary.
The value you are retrieving is probably a UUID. You either need to use the value as a binary, or select a human 'readable' UUID string using UUID_TO_CHAR:
SELECT FIRST 1 UUID_TO_CHAR(UID) FROM cmd

byte[] to string an string to byte[]

i know this was handled a lot here, but i couldnt solve my problem yet:
I read bytes from a Parceble Object and save them in a byte[], then I unmurshall
them back to an Object an it works all fine. But i have to send the bytes as a String, so i
have to convert the bytes to string and then return.
I thought it would work as follow:
byte[] bytes = p1.marshall(); //get my object as bytes
String str = bytes.toString();
byte[] someBytes = str.getBytes();
But it doesnt Work, when I "p2.unmarshall(someBytes, 0, someBytes.length);" with someBytes, but when I p2.unmarshall(bytes, 0, bytes.length); with bytes, it works fine. How can i convert bytes to String right?
You've got three problems here:
You're calling toString() on byte[], which is just going to give you something like "[B#15db9742"
You're assuming you can just convert a byte array into text with no specific conversion, and not lose data
You're calling getBytes() without specifying the character encoding, which is almost always a mistake.
In this case, you should just use base64 - that's almost always the right thing to do when converting arbitrary binary data to text. (If you were actually trying to decode encoded text, you should use new String(bytes, charset), but that's not the case here.)
So, using android.util.Base64:
String str = Base64.encodeToString(bytes, Base64.DEFAULT);
byte[] someBytes = Base64.decode(str, Base64.DEFAULT);

java.lang.NumberFormatException or java.nio.BufferUnderflowException when transforming bytes

I played around with some String -> byte -> binary code and I want my code to work for any byte[] array, currently it only works for, I am not sure ascii?
chinese DONT WORK.
String message =" 汉语";
playingWithFire(message.getBytes());
while String wow = "WOW..."; Works :( I want it to work for all utf-8 formates. Any pointers on how I can do it?
//thanks
public static byte[] playingWithFire(byte[] bytes){
byte[] newbytes = null;
newbytes = new byte[bytes.length];
for(int i = 0; i < bytes.length; i++){
String tempStringByte = String.format("%8s", Integer.toBinaryString(bytes[i] & 0xFF)).replace(' ', '0');
StringBuffer newByteBrf = null;
newByteBrf = new StringBuffer();
for(int x = 0; x < tempStringByte.length(); x++){
newByteBrf.append(tempStringByte.charAt(x));
}
/*short a = Short.parseShort(newByteBrf.toString(), 2);
ByteBuffer bytesads = ByteBuffer.allocate(2).putShort(a);
newbytes[i] = bytesads.get();
cause: java.nio.BufferUnderflowException
*/
//cause: java.lang.NumberFormatException: Value out of range.
newbytes[i] = Byte.parseByte(newByteBrf.toString(), 2);
}
return newbytes;
}
message.getBytes() in your case is trying to convert Chinese Unicode characters to bytes using the default character set on your computer. If its a western charset, its going to be wrong.
Notice that String.getBytes() has another form with String.getBytes(String) where the string is the name of a character encoding that is used to convert the chars of the string to bytes.
The char type will hold Unicode. The byte type only holds raw bits in groups of 8.
So, to convert a Unicode string to bytes encoded as UTF-16 you would use this code:
String message =" 汉语";
byte[] utf16Bytes = message.getBytes("utf-16");
Substitute the name of any encoding that you want to use.
Similarly new String(String, byte[]) constructor can take an array of bytes encoded in some fashion and, given the String, can convert those bytes to Unicode characters.
For example: If you want to convert those bytes, which were encoded as utf-16 above, back to a String (which has Unicode chars in it):
String newMessage = new String(utf16Bytes, "utf-16");
Since I don't know what you mean by "binary code" above, I can't go much farther. As I see it, the Unicode chars have a binary code inside them that represents the characters one-by-one. Also the byte array has a binary code in it that represents the characters with a many-bytes-to-one-character representation. If you want to encrypt the byte array somehow, use a standard, proven encryption method and proven, time-tested procedures to secure the contents.

memcached client throws java.lang.IllegalArgumentException: Key contains invalid characters

Seems memcache client doesn't support UTF-8 string as its key. But I have to use i18n. Anyway to fix it?
java.lang.IllegalArgumentException: Key contains invalid characters: ``HK:00:A Kung Wan''
at net.spy.memcached.MemcachedClient.validateKey(MemcachedClient.java:232)
at net.spy.memcached.MemcachedClient.addOp(MemcachedClient.java:254)
The issue here isn't UTF encoding. It's the fact that your key contains a space. Keys cannot have spaces, new lines, carriage returns, or null characters.
The line of code that produces the exception is below
if (b == ' ' || b == '\n' || b == '\r' || b == 0) {
throw new IllegalArgumentException
("Key contains invalid characters: ``" + key + "''");
}
Base64 Encode your key just before passing them to memcached client's set() and get() methods.
A general solution to handle all memcached keys with special characters, control characters, new lines, spaces, unicode characters, etc. is to base64 encode the key just before you pass it to the set() and get() methods of memcached.
// pseudo code for set
memcachedClient.set(Base64.encode(key), value);
// pseudo code for get
memcachedClient.get(Base64.encode(key));
This converts them into characters memcached is guaranteed to understand.
In addition, base64 encoding has no performance penalty (unless you are a nano performance optimization guy), base64 is reliable and takes only about 30% extra length.
Works like a charm!

Encryption key in CodeIgniter

The CodeIgniter 2.0.2 requires to set an encryption key in the config file i.e. $config['encryption_key'] , if you want to use Session class. Can it be any string? Any example of secure encryption_key?
Thanks.
The key should be as random as possible and it must not be a regular
text string, nor the output of a hashing function, etc.
To save your key to your application/config/config.php, open the file and set:
$config['encryption_key'] = 'yourKeyHere'
Random Key Generator
It's important for you to know that the encoded messages the encryption function generates will be approximately 2.6 times longer than the original message. For example, if you encrypt the string "my super secret data", which is 21 characters in length, you'll end up with an encoded string that is roughly 55 characters (we say "roughly" because the encoded string length increments in 64 bit clusters, so it's not exactly linear). Keep this information in mind when selecting your data storage mechanism. Cookies, for example, can only hold 4K of information.
In addition to the answer by Chumillas, I personally use this Random Key Generator for my CodeIgniter encryption strings. Quick and easy.
Codeigniter 3.1.0
YOU MUST NOT USE REGULAR TEXT FOR 'encryption_key'
"The key should be as random as possible and it must not be a regular text string, nor the output of a hashing function, etc. In order to create a proper key, you must use the Encryption library’s create_key() method"
$this->load->library('encryption');
$key = $this->encryption->create_key(16);
// Get a hex-encoded representation of the key:
$key = bin2hex($this->encryption->create_key(16));
// Put the same value in your config with hex2bin(),
// so that it is still passed as binary to the library:
$config['encryption_key'] = hex2bin(<your hex-encoded key>);
Source: https://codeigniter.com/userguide3/libraries/encryption.html#setting-your-encryption-key
Type this into your terminal:
php -r 'echo bin2hex(random_bytes(16)), "\n";'
It'll output a string where you update your config.php
Just go to application/config
open config.php file
find out the word
$config['encryption_key'] = '';
replace this with
$config['encryption_key'] = 'your_encryption_key_here';
I am using the following code in my app's installer. It takes 128 bytes of random data (converted to a hex string), and takes two characters at a time, converting to decimal, and checking they're in an acceptable range (alphanumeric, with symbols, no whitespace or characters that won't play nice with your editor or config file - aka no ')
32 characters is 128 bits, so it works well with the block cipher.
function random_key_string() {
$source = bin2hex(openssl_random_pseudo_bytes(128));
$string = '';
$c = 0;
while(strlen($string) < 32) {
$dec = gmp_strval(gmp_init(substr($source, $c*2, 2), 16),10);
if($dec > 33 && $dec < 127 && $dec !== 39)
$string.=chr($dec);
$c++;
}
return $string;
}
To save your key to your application/config/config.php, open the file and set:
on line 227 $config['encryption_key'] = "YOUR KEY";

Resources