Simple two-way encryption to generate encrypted key with no special character - encryption

I have a simple two way encryption method which generates encrypted string. The method is given below:-
public function cryption($string, $action = 'e')
{
$secret_key = 'secret-key';
$secret_iv = 'secret_iv';
$output = false;
$encrypt_method = "AES-256-CBC";
$key = hash( 'sha256', $secret_key );
$iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
if( $action == 'e' ){
$output = openssl_encrypt( $string, $encrypt_method, $key, 0, $iv );
}else if( $action == 'd' ){
$output = openssl_decrypt( $string, $encrypt_method, $key, 0, $iv );
}
return $output;
}
The problem is, it creates a string like this-
yTJbtH7mIJjhY+SatnTxY5i2jt/qUW+nZgmGBeBgZEzpy2GMSBQgDjKeyjxGOdJd
Such encrypted keys have chars like / & +. I want a simple two way encryption which could generate string consisting of only alphanumeric characters.
Note: This string will be sent as parameter to a codeigniter controller method. Having slashes means the portion of the string after a slash will be treated as a separate parameter.

I am not a crypto expert, so I can't tell if there is an encryption or hashing method which produces only alphanumeric characters in its encrypted / hashed output.
However, I believe I can help you solve the underlying problem. This is one of the typical cases where escaping comes in handy. In the following, I will provide an over-simplified example which will show the concept.
So let us assume that the + character is the only forbidden character and that your cryptographic functions have output the string ab+cyk; this would be the value of $output in your code.
Now let us define the following replacement of character sequences:
+ <-> ya
i.e. you are doing a further processing of $output before sending it, where + gets replaced by ya. This way, you have eliminated all + characters from $output.
When the codeigniter controller receives that string, it first de-escapes (unescapes) it, applying the reverse process. In this case, it would replace all occurrences of ya by + to get the original encrypted string back, and can then (cryptographically) decrypt the result.
Now we are almost there, but we have one problem left. Currently the receiver (controller) can't distinguish if the character sequence ya in the received string actually indeed means ya or if it means +.
We can solve that problem if we define another replacement which must be applied by the sender and the receiver:
y <-> yy
Now, the character sequence ya, when encountered by the controller in the received string, would be unambiguous. It would mean + because the original sequence ya would have been escaped (encoded) as yya.
Coming back to our over-simplified example, the string ab+cyk would become abyacyyk at the sender's side and could be unambiguously decoded by the receiver (controller).
This principle (with variations) has been applied in countless standards and situations in software development. The most famous which immediately come to my mind are C (where the backslash has a special meaning in string constants, so the backslash is the escape character) and the escaping of URIs (where the percent sign is the escape character).
Of course, in our example, the y character is the escape character. Please note that we are not urged to double the escape character if we want to have it literally; this is just a random (though frequent) choice. In our example, we could have escaped y by yz or something else instead of yy.
Given your reputation, I am convinced that you are able to write an appropriate encoding and decoding function within minutes, and that you easily can extend the example to escape other unwanted characters as well (for example, escape / as yb). If you need help, please leave a comment, and I'll add appropriate pseudo-code to my answer.
But eventually, there already is a solution: If you can accept percent signs (%) in the string the sender sends to the receiver (controller), you can simply use URI escaping.
The key point here is that every (scripting) language I know of has modules or even core functions which do URI escaping and unescaping (also called URI encoding and decoding) reliably, comfortably and (last, but not least) efficiently. In most cases, you even can tell those modules / functions which characters you would like to have escaped and which not, in case you would like to deviate from the usual character sets.
The only disadvantage of this solution is that it may increase the size of the payload, and that you can't predict the size before actually having encoded the payload.
For example, if we would encode and decode as described above, the size of our string would be doubled upon encoding if it would contain only + and y characters. If we would apply URI encoding, the string size even could be tripled (because a character to be escaped would be replaced by a percent sign plus the hexadecimal code of the character, i.e. A would be replaced by %41, for example (if A would be in the character set to be replaced)).
Given today's bandwidth, storage and RAM speed and CPU power, I don't suppose that this becomes a real problem in your case.

Related

Semicolon in URLs

I have a URL like that: localhost:8080/demo/
And when I call localhost:8080/demo/''''''''' It working fine.
But when I try with localhost:8080/demo/;;; It not working and return HTTP code 404 Not Found.
I tried with few special character # % \ ? / , it returned 400 too.
Anyone can explain it for me?
Thank you so much!
These special characters are not directly allowed in URLs,
because they have special meanings there.
For example:
/ is separator within the path,
? marks the query-part of an URL,
# marks a page-internal link,
etc.
Quoted from Wikipedia: Percent-encoding reserved characters:
When a character from the reserved set (a "reserved character")
has special meaning (a "reserved purpose") in a certain context,
and a URI scheme says that it is necessary to use that character
for some other purpose, then the character must be percent-encoded.
Percent-encoding a reserved character involves converting the
character to its corresponding byte value in ASCII and then
representing that value as a pair of hexadecimal digits. The digits,
preceded by a percent sign (%) which is used as an escape character,
are then used in the URI in place of the reserved character.
For example: ; is a reserved character. Therefore, when ; shall occur
in an URL but without having its special meaning, then it needs to be
replaced by %3B as defined here

Using Coldfusion's Encrypt function to encrypt a hex block and return a block-length result

My company is working on a project that will put card readers in the field. The readers use DUKPT TripleDES encryption, so we will need to develop software that will decrypt the card data on our servers.
I have just started to scratch the surface on this one, but I find myself stuck on a seemingly simple problem... In trying to generate the IPEK (the first step to recreating the symmetric key).
The IPEK's a 16 byte hex value created by concatenating two triple DES encrypted 8 byte hex strings.
I have tried ECB and CBC (zeros for IV) modes with and without padding, but the result of each individual encoding is always 16 bytes or more (2 or more blocks) when I need a result that's the same size as the input. In fact, throughout this process, the cyphertexts should be the same size as the plaintexts being encoded.
<cfset x = encrypt("FFFF9876543210E0",binaryEncode(binaryDecode("0123456789ABCDEFFEDCBA98765432100123456789ABCDEF", "hex"), "base64") ,"DESEDE/CBC/PKCS5Padding","hex",BinaryDecode("0000000000000000","hex"))>
Result: 3C65DEC44CC216A686B2481BECE788D197F730A72D4A8CDD
If you use the NoPadding flag, the result is:
3C65DEC44CC216A686B2481BECE788D1
I have also tried encoding the plaintext hex message as base64 (as the key is). In the example above that returns a result of:
DE5BCC68EB1B2E14CEC35EB22AF04EFC.
If you do the same, except using the NoPadding flag, it errors with "Input length not multiple of 8 bytes."
I am new to cryptography, so hopefully I'm making some kind of very basic error here. Why are the ciphertexts generated by these block cipher algorithms not the same lengths as the plaintext messages?
For a little more background, as a "work through it" exercise, I have been trying to replicate the work laid out here:
https://www.parthenonsoftware.com/blog/how-to-decrypt-magnetic-stripe-scanner-data-with-dukpt/
I'm not sure if it is related and it may not be the answer you are looking for, but I spent some time testing bug ID 3842326. When using different attributes CF is handling seed and salt differently under the hood. For example if you pass in a variable as the string to encrypt rather than a constant (hard coded string in the function call) the resultant string changes every time. That probably indicates different method signatures - in your example with one flag vs another flag you are seeing something similar.
Adobe's response is, given that the resulting string can be unecrypted in either case this is not really a bug - more of a behavior to note. Can your resultant string be unencrypted?
The problem is encrypt() expects the input to be a UTF-8 string. So you are actually encrypting the literal characters F-F-F-F-9.... rather than the value of that string when decoded as hexadecimal.
Instead, you need to decode the hex string into binary, then use the encryptBinary() function. (Note, I did not see an iv mentioned in the link, so my guess is they are using ECB mode, not CBC.) Since the function also returns binary, use binaryEncode to convert the result to a more friendly hex string.
Edit: Switching to ECB + "NoPadding" yields the desired result:
ksnInHex = "FFFF9876543210E0";
bdkInHex = "0123456789ABCDEFFEDCBA98765432100123456789ABCDEF";
ksnBytes = binaryDecode(ksnInHex, "hex");
bdkBase64 = binaryEncode(binaryDecode(bdkInHex, "hex"), "base64");
bytes = encryptBinary(ksnBytes, bdkBase64, "DESEDE/ECB/NoPadding");
leftRegister = binaryEncode(bytes, "hex");
... which produces:
6AC292FAA1315B4D
In order to do this we want to start with our original 16 byte BDK
... and XOR it with the following mask ....
Unfortunately, most of the CF math functions are limited to 32 bit integers. So you probably cannot do that next step using native CF functions alone. One option is to use java's BigInteger class. Create a large integer from the hex strings and use the xor() method to apply the mask. Finally, use the toString(radix) method to return the result as a hex string:
bdkText ="0123456789ABCDEFFEDCBA9876543210";
maskText = "C0C0C0C000000000C0C0C0C000000000";
// use radix=16 to create integers from the hex strings
bdk = createObject("java", "java.math.BigInteger").init(bdkText, 16);
mask = createObject("java", "java.math.BigInteger").init(maskText, 16);
// apply the mask and convert the result to hex (upper case)
newKeyHex = ucase( bdk.xor(mask).toString(16) );
WriteOutput("<br>newKey="& newKeyHex);
writeOutput("<br>expected=C1E385A789ABCDEF3E1C7A5876543210");
That should be enough to get you back on track. Given some of CF's limitations here, java would be a better fit IMO. If you are comfortable with it, you could write a small java class and invoke that from CF instead.

What causes XOR encryption to return a "blank"?

What is the cause of certain characters to be blank when using XOR encryption? Furthermore, how can this be compensated for when decrypting?
For instance:
....
void basic_encrypt(char *to_encrypt) {
char c;
while (*to_encrypt) {
*to_encrypt = *to_encrypt ^ 20;
to_encrypt++;
}
}
will return "nothing" for the character k. Clearly, character decay is problematic for decryption.
I assume this is caused by the bit operator, but I am not very good with binary so I was wondering if anyone could explain.
Is it converting an element, k, in this case, to some spaceless ASCII character? Can this be compensated for by choosing some y < x < z operator where x is the operator?
Lastly, if it hasn't been compensated for, is there a realistic decryption strategy for filling in blanks besides guess and check?
'k' has the ASCII value 107 = 0x6B. 20 is 0x14, so
'k' ^ 20 == 0x7F == 127
if your character set is ASCII compatible. 127 is \DEL in ASCII, which is a non-printable character, so won't be displayed if you print it out.
You will have to know the difference between bytes and characters to understand which is happening. On the one hand you have the C char type, which is simply a presentation of a byte, not a character.
In the old days each character was mapped to one byte or octet value in a character encoding table, or code page. Nowadays we have encodings that take more bytes for certain characters, e.g. UTF-8, or even encodings that always take more than one byte such as UTF-16. The last two are unicode encodings, which means that each character has a certain number value and the encoding is used to encode this number into bytes.
Many computers will interpret bytes in ISO/IEC 8859-1 or Latin-1, sometimes extended by Windows-1252. These code pages have holes for control characters, or byte values that are simply not used. Now it depends on the runtime system how these values are handled. Java by default substitutes an ? character in place of the missing character. Other runtimes will simply drop the value or - of course - execute the control code. Some terminals may use the ESC control code to set the color or to switch to another code page (making a mess of the screen).
This is why ciphertext should be converted to another encoding, such as hexadecimals or Base64. These encodings should make sure that the result is readable text. This takes care of the cipher text. You will have to choose a character set for your plain text too, e.g. simply perform ASCII or UTF-8 encoding before encryption.
Getting a zero value from encryption does not matter because once you re-xor with the same xor key you get the original value.
value == value
value XOR value == 0 [encryption]
( value XOR value ) XOR value == value [decryption]
If you're using a zero-terminated string mechanism, then you have two main strategies for preventing 'character degradation'
store the length of the string before encryption and make sure to decrypt at least that number of characters on decryption
check for a zero character after decoding the character

Need Regular Expression for this(C#)

Updated::
Password strength:
Contain characters from three of the following four categories:
English uppercase characters (A through Z)
English lowercase characters (a through z)
Base 10 digits (0 through 9)
Non-alphabetic characters (for example, !, $, #, %
IS it possible to compare two fields value(entered) with regex...if yes then please add onr another condition to above list.
compare password with username entered they must be different
EDIT: This answer was written before the question was edited. It originally included the requirement to not include the user's account name, and be at least 8 characters long.
Given that you need to use the user's account name as part of it anyway, is there any reason you particularly want to do this as a regular expression? You may want to use regular expressions to express the patterns for the four categories (although there are other ways of doing it too) but I would write the rules out separately. For example:
// Categories is a list of regexes in this case. You could easily change
// it to anything else.
int categories = Categories.Count(regex => regex.IsMatch(password));
bool valid = password.IndexOf(name, StringComparison.OrdinalIgnoreCase) == -1
&& password.Length >= 8
&& categories >= 3;
If you need to do it in one expression it should be something like this:
^(?:(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])|(?=.*[a-z])(?=.*[A-Z])(?=.*[!%,.;:])|(?=.*[a-z])(?=.*[0-9])(?=.*[!%,.;:])|(?=.*[A-Z])(?=.*[0-9])(?=.*[!%,.;:])).{8,}$
See it here on Regexr
Positive lookaheads (the (?=.*[a-z])) are used to check if the string contains the character group you want.
The problem here is, you want 3 out of 4, that means you have to make an alternation with all the allowed combinations.
The last part .{8,} is then matching the string and checking for at least 8 characters.
^ and $ are anchors, that anchor the pattern to the start and the end of the string.
[!%,.;:] is a character class, here you can add all the characters you want to include. Maybe its simpler to use a Unicode script like \p{P} for all punctuation characters. For more details see here on regular-expresssions.info
Update
compare password with username entered they must be different
normally you should be able to build up your regular expression using string concatenation. I have no idea how it is in your case where you put the regex ...
Something like this (pseudo)
String Username = "FooBar";
regex = "^(?:(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])|(?=.*[a-z])(?=.*[A-Z])(?=.*[!%,.;:])|(?=.*[a-z])(?=.*[0-9])(?=.*[!%,.;:])|(?=.*[A-Z])(?=.*[0-9])(?=.*[!%,.;:]))(?i)(?!.*" + Username + ").+$";
I used here also an inline modifier (?i) to match it case independent. The (?!.* is the start of negative lookahead, meaning the string should not contain ...

Multiple Base64 encoded parameters that appear as 1 in a URL query string

I need to pass 2 parameters in a query string but would like them to appear as a single parameter to the user. At a low level, how can I concatinate these two values and then later separate them? Both values are Base64 encoded.
?Name=abcyxz
where both abc and xyz are separate Base64 encoded strings.
why don't you just do something like this
temp = base64_encode("var1=abc&var2=yxz")
and then call
?Name=temp
Later you can decode the whole string and split the vars.
(sry for pseudo code :P)
Edit: a small quote from wikipedia
The current version of PEM (specified in RFC 1421) uses a 64-character alphabet consisting of upper- and lower-case Roman alphabet characters (A–Z, a–z), the numerals (0–9), and the "+" and "/" symbols. The "=" symbol is also used as a special suffix code. The original specification, RFC 989, additionally used the "*" symbol to delimit encoded but unencrypted data within the output stream.
You should either use some separator or store the length of the first item.
First of all, I would be curious as to why you can't just pass two parameters. But with that as a given, just choose any character that's a valid character in a URL query string, but won't show up in your base64 encoding, such as ~

Resources