I have been trying out to ''improve'' the simple Caesar encryption by encrypting in the CBC mode.
As I understand, the first character has to be XORed by an initialization vector and then by the key, the output then is the first character of the encrypted text. This will then be XORed by the second char, then again XORed by the key, … and so forth.
I don't quite understand how the XORing should work.
Let us have the translation table given (only space and A-Z):
/s: 0, A: 1, B: 2, …, Z: 26,
key: 1,
Init.vector: 5
Using the simple Caesar, ''HELLO'' -> {8,5,12,12,20} -> {9,6,13,13,21} -> ''IFMMP''
But how would I get to encrypt using CBC?
It'd be especially helpful if you could show me how to implement it in Java. Thanks!
Hmm I interpret your question like you think you want to xor by the key to your cipher, this is wrong:
You xor by the previous result from the cipher. Something like this:
// Untested code
// The code below need to be adjusted for it to print meaningful
// characters in the encrypted string as the xor function produces
// integers outside the range of standard ascii characters
private void cbcCaesar(){
int key = 1;
String message = "java";
int initialisationVector = 5; // the IV is not super necessarily hidden from an attacker but should be different for each message
StringBuilder encryptedMessageBuilder = new StringBuilder();
char[] charArray = message.toCharArray();
int encryptedLetter = initialisationVector;
for (int letter : charArray){
int xorApplied = letter ^ encryptedLetter;
encryptedLetter = applyCaesarCipher(xorApplied, key);
encryptedMessageBuilder.append((char) encryptedLetter);
}
System.out.println(encryptedMessageBuilder.toString());
}
private int applyCaesarCipher(int xorApplied, int key) {
return (xorApplied+ key) % 26;
}
The easiest way to convert the above snippet to something usable would be to map letters to the numbers 0-26 and use that instead of the char's ascii encoding
I found this resource to be pretty good https://www.youtube.com/watch?v=0D7OwYp6ZEc
Related
I'm writing a Simplified DES algorithm to encrypt and subsequently decrypt a string. Suppose I have the initial character ( which has the binary value 00101000 which I get using the following algorithm:
public void getBinary() throws UnsupportedEncodingException {
byte[] plaintextBinary = text.getBytes("UTF-8");
for(byte b : plaintextBinary){
int val = b;
int[] tempBinRep = new int[8];
for(int i = 0; i<8; i++){
tempBinRep[i] = (val & 128) == 0 ? 0 : 1;
val <<= 1;
}
binaryRepresentations.add(tempBinRep);
}
}
After I perform the various permutations and shifts, ( and it's binary equivalent is transformed into 10001010 and it's ASCII equivalent Š. When I come around to decryption I pass the same character through the getBinary() method I now get the binary string 11000010 and another binary string 10001010 which translates into ASCII as x(.
Where is this rogue x coming from?
Edit: The full class can be found here.
You haven't supplied the decrypting code, so we can't know for sure, but I would guess you missed the encoding either when populating your String. Java Strings are encoded in UTF-16 by default. Since you're forcing UTF-8 when encrypting, I'm assuming you're doing the same when decrypting. The problem is, when you convert your encrypted bytes to a String for storage, if you let it default to UTF-16, you're probably ending up with a two-byte character because the 10001010 is 138, which is beyond the 127 range for ASCII charaters that get represented with a single byte.
So the "x" you're getting is the byte for the code page, followed by the actual character's byte. As suggested in the comments, you'd do better to just store the encrypted bytes as bytes, and not convert them to Strings until they're decrypted.
I am creating an encryption algorithm and is to XOR two strings. While I know how to XOR the two strings the problem is the length. I have two byte arrays one for the plain text which is of a variable size and then the key which is of 56 bytes lets say. What I want to know is what is the correct method of XORing the two strings. Concatenate them into one String in Binary and XOR the two values? Have each byte array position XOR a concatenated Binary value of the key and such. Any help is greatly appreciated.
Regards,
Milinda
To encode just move through the array of bytes from the plain text, repeating the key as necessary with the mod % operator. Be sure to use the same character set at both ends.
Conceptually we're repeating the key like this, ignoring encoding.
hello world, there are sheep
secretsecretsecretsecretsecr
Encrypt
String plainText = "hello world, there are sheep";
Charset charSet = Charset.forName("UTF-8");
byte[] plainBytes = plainText.getBytes(charSet);
String key = "secret";
byte[] keyBytes = key.getBytes(charSet);
byte[] cipherBytes = new byte[plainBytes.length];
for (int i = 0; i < plainBytes.length; i++) {
cipherBytes[i] = (byte) (plainBytes[i] ^ keyBytes[i
% keyBytes.length]);
}
String cipherText = new String(cipherBytes, charSet);
System.out.println(cipherText);
To decrypt just reverse the process.
// decode
for (int i = 0; i < cipherBytes.length; i++) {
plainBytes[i] = (byte) (cipherBytes[i] ^ keyBytes[i
% keyBytes.length]);
}
plainText = new String(plainBytes, charSet); // <= make sure same charset both ends
System.out.println(plainText);
(As noted in comments, you shouldn't use this for anything real. Proper cryptography is incredibly hard to do properly from scratch - don't do it yourself, use existing implementations.)
There's no such concept as "XOR" when it comes to strings, really. XOR specifies the result given two bits, and text isn't made up of bits - it's made up of characters.
Now you could just take the Unicode representation of each character (an integer) and XOR those integers together - but the result may well be a sequence of integers which is not a valid Unicode representation of any valid string.
It's not clear that you're even thinking in the right way to start with - you talk about having strings, but also having 56 bytes. You may have an encoded representation of a string (e.g. the result of converting a string to UTF-8) but that's not the same thing.
If you've got two byte arrays, you can easily XOR those together - and perhaps cycle back to the start of one of them if it's shorter than the other, so that the result is always the same length as the longer array. However, even if both inputs are (say) UTF-8 encoded text, the result often won't be valid UTF-8 encoded text. If you must have the result in text form, I'd suggest using Base64 at that point - there's a public domain base64 encoder which has a simple API.
I´m using this code to Encrypt and Decrypt in Java and Android some Strings and in each system I get a different value.
The code I'm using comes from http://www.androidsnippets.com/encryptdecrypt-strings (I won't paste it beacuse it's quite big).
For example in Android for encrypting "aa" I get this:
1C6BD31C57F42ACFD0EDD2DD5B7A92CA
and exactly the same String with the same key as seed in Java I get:
61FAD1203B7AC92AD9345771AA273DA5
Any idea?
Thanks in advance!
This is just my guess, but I think the reason is your key derivation. I'm not really a Java developer though, so I might not be understanding the code correctly.
This code always calls getRawKey() when you encrypt and decrypt. getRawKey() looks like it takes something they call a seed, or your shared secret, and uses it to compute a new random key to do the actual encryption/decryption.
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
According to Java docs found here, setSeed() "Reseeds this random object. The given seed supplements, rather than replaces, the existing seed."
My guess is that the initial state of the RNG is different on each system/platform, and thus it's giving you different results. You should fix the key derivation to something more standard and consistent, or use an already established crypto system, like PGP in the Bouncy Castle libraries.
This example will demonstrate to how to encrypt a sting and decrypt, for that purpose we need a shif key which will shift the one character to another character, for exaple if you have 'b' and using shift key=2 then it will becom 98+2=100 which ='d' and again 100-2=98 which is 'b', so this will perform in this way.
Make your String encrypt here !
final int shift_key = 4; //it is the shift key to move charcter, like if i have 'a' then a=97+4=101 which =e and thus it changes
String plainText = "piran jhandukhel";
char character;
char ch[]=new char[plainText.length()];//for storing encrypt char
for (int iteration = 0; iteration < plainText.length(); iteration++)
{
character = plainText.charAt(iteration); //get characters
character = (char) (character + shift_key); //perform shift
} ch[iteration]=character;//assign char to char array
String encryptstr = String.valueOf(ch);//converting char array to string
Toast.makeText(this, "Encrypt string is "+ encryptstr Toast.LENGTH_LONG).show();
Make Your String Decrypt here !
for(int i=0;i<encryptstr.length();i++)
{
character=str.charAt(i);
character = (char) (character -shift_key); //perform shift
ch[i]=character;
}
Stirng decryptstr = String.valueOf(ch);
Toast.makeText(this, "Decrypted String is "+decryptstr, Toast.LENGTH_LONG).show();
Looks like it will have different output every time you encrypt it. This is normal.
I am new to java but I am very fluent in C++ and C# especially C#. I know how to do xor encryption in both C# and C++. The problem is the algorithm I wrote in Java to implement xor encryption seems to be producing wrong results. The results are usually a bunch of spaces and I am sure that is wrong. Here is the class below:
public final class Encrypter {
public static String EncryptString(String input, String key)
{
int length;
int index = 0, index2 = 0;
byte[] ibytes = input.getBytes();
byte[] kbytes = key.getBytes();
length = kbytes.length;
char[] output = new char[ibytes.length];
for(byte b : ibytes)
{
if (index == length)
{
index = 0;
}
int val = (b ^ kbytes[index]);
output[index2] = (char)val;
index++;
index2++;
}
return new String(output);
}
public static String DecryptString(String input, String key)
{
int length;
int index = 0, index2 = 0;
byte[] ibytes = input.getBytes();
byte[] kbytes = key.getBytes();
length = kbytes.length;
char[] output = new char[ibytes.length];
for(byte b : ibytes)
{
if (index == length)
{
index = 0;
}
int val = (b ^ kbytes[index]);
output[index2] = (char)val;
index++;
index2++;
}
return new String(output);
}
}
Strings in Java are Unicode - and Unicode strings are not general holders for bytes like ASCII strings can be.
You're taking a string and converting it to bytes without specifying what character encoding you want, so you're getting the platform default encoding - probably US-ASCII, UTF-8 or one of the Windows code pages.
Then you're preforming arithmetic/logic operations on these bytes. (I haven't looked at what you're doing here - you say you know the algorithm.)
Finally, you're taking these transformed bytes and trying to turn them back into a string - that is, back into characters. Again, you haven't specified the character encoding (but you'll get the same as you got converting characters to bytes, so that's OK), but, most importantly...
Unless your platform default encoding uses a single byte per character (e.g. US-ASCII), then not all of the byte sequences you will generate represent valid characters.
So, two pieces of advice come from this:
Don't use strings as general holders for bytes
Always specify a character encoding when converting between bytes and characters.
In this case, you might have more success if you specifically give US-ASCII as the encoding. EDIT: This last sentence is not true (see comments below). Refer back to point 1 above! Use bytes, not characters, when you want bytes.
If you use non-ascii strings as keys you'll get pretty strange results. The bytes in the kbytes array will be negative. Sign-extension then means that val will come out negative. The cast to char will then produce a character in the FF80-FFFF range.
These characters will certainly not be printable, and depending on what you use to check the output you may be shown "box" or some other replacement characters.
I have two numbers: one is an int, other is byte. I want to create a single long value out of them in a way that person knowing the byte value can decipher original int from it. Whats the best way to do it?
Assuming i understood your question correct,
The Simplest Solution, You Could XOR the 'int' using the 'byte'
Repeat the process to decrypt...
byte key = 8;
int secret = 123;
System.out.println("Secret : " + secret);
int encrypted = (secret ^ (key | (key << 8)));
System.out.println("Encrypted : " + encrypted );
int decrypt = (encrypted ^ (key | (key << 8)));
System.out.println("Decrypted : " + decrypt );
The result is an 'int' but, you could always just cast it into a long...
long mylong = (((long)mybyte) << 40) | myint;
To retrieve the original value:
int myorigint = (int)(mylong & ~(((long)mybyte) << 40));
But this requires 8-byte longs. Which are not required by the C standard. If a long is 4 bytes, you're out of luck. This means long and int would have the same length. If sizeof(int)==sizeof(long)==4, then asking to store an int and a byte in a long is asking to store 5 arbitrary bytes of information in 4 bytes. Which is completely impossible.
Of course, there's also the trivial "solution":
long mylong = (long)myint;
and the reverse is:
int myint = (int)mylong;
Now, someone knowing (or not knowing!) the byte can retrieve the original data.
If you want a solution such that only someone knowing the correct byte can retrieve the original int, you can use this:
long mylong = (long)(myint-mybyte);
and reverse:
int myint = (int)(mylong+mybyte);
But know that encrypting four bytes with one byte will not be truly secure. You should use a 4-byte one-time pad to encrypt four bytes. If you have a four-byte key, use XOR for a truly unbreakable cipher. No, really.
One idea is to apply a reversible function the number of times indicated by the byte.
To get the original number back just apply the inverse function the same number of times.
e.g.
public static int encrypt(int value, byte key) {
int result=value;
for (int i=0; i<=(key&255); i++) {
result=Integer.rotateRight(result,7)^(i+0xCAFEBABE);
}
return result;
}
Finding the reverse function left as an exercise for the reader.....