Switch from using a class to using a method - java

So I've been working on this bit of code for awhile now. It's about encrypting and decrypting a message and producing the two keys used alternatively to encrypt a message using the Caesar Cipher method of changing letters with corresponding letters from a shifted alphabet. For example "Fruit" would be "Hwwnv" according to the shifted alphabets found by implementing +2 to every other letter starting with the first letter, and implementing +5 to every other letter starting with the second letter. I've been using an instance of another class called BreakCaesarThree to find these two keys, dkey_0 and dkey_1 and a decrypted message. I would rather use my method breakCaesarTwo instead, because of the ease of having all my necessary code in one class. How would I go about doing this? How do I change it so that I'm using breakCaesarTwo method instead of BreakCaesarThree class, and still be able to print out the dkey_0 and dkey_1 and a decrypted message? I am hoping that changing to using the breakCaesarTwo method will yield the right results.
Note: Right now calling BreakCaesarThree doesn't yield a decrypted message or give the right keys (I get 0s).
Here's my TestCaesarCipherTwo code which includes the breakCaesarTwo method:
import edu.duke.*;
public class TestCaesarCipherTwo {
private String alphabetLower;
private String alphabetUpper;
private String shiftedAlphabetLower1;
private String shiftedAlphabetUpper1;
private String shiftedAlphabetLower2;
private String shiftedAlphabetUpper2;
private int mainKey1;
private int mainKey2;
private int dkey_0;
private int dkey_1;
/**
*
*/
public void simplebreaker()
{
FileResource fr = new FileResource();
String encrypted = fr.asString();
BreakCaesarThree bct = new BreakCaesarThree();
String broken = bct.decrypt(encrypted);
System.out.println("Keys found: " + bct.dkey_0 + ", " + bct.dkey_1 + "\n" + broken);
}
public String halfOfString(String message, int start) {
StringBuilder halfString = new StringBuilder();
for (int index=start;index < message.length();index += 2) {
halfString.append(message.charAt(index));
}
return halfString.toString();
}
public String decrypt(String input) {
CaesarCipherTwoKeys cctk= new CaesarCipherTwoKeys(26 - mainKey1, 26 - mainKey2);
String decrypted = cctk.encrypt(input);
return decrypted;
}
public int[] countOccurrencesOfLetters(String message) {
//snippet from lecture
String alph = "abcdefghijklmnopqrstuvwxyz";
int[] counts = new int[26];
for (int k=0; k < message.length(); k++) {
char ch = Character.toLowerCase(message.charAt(k));
int dex = alph.indexOf(ch);
if (dex != -1) {
counts[dex] += 1;
}
}
return counts;
}
public int maxIndex(int[] values) {
int maxDex = 0;
for (int k=0; k < values.length; k++) {
if (values[k] > values[maxDex]) {
maxDex = k;
}
}
return maxDex;
}
public void simpleTests()
{
int key1 = 17;
int key2 = 3;
FileResource fr = new FileResource();
String message = fr.asString();
CaesarCipherTwoKeys cctk = new CaesarCipherTwoKeys(key1, key2);
String encrypted = cctk.encrypt(message);
System.out.println(encrypted);
String decrypted = cctk.decrypt(encrypted);
System.out.println(decrypted);
BreakCaesarThree bct = new BreakCaesarThree();
String broken = bct.decrypt(encrypted);
System.out.println("Keys found: " + bct.dkey_0 + ", " + bct.dkey_1 + "\n" + broken);
}
public String breakCaesarTwo(String input) {
String in_0 = halfOfString(input, 0);
String in_1 = halfOfString(input, 1);
// Find first key
// Determine character frequencies in ciphertext
int[] freqs_0 = countOccurrencesOfLetters(in_0);
// Get the most common character
int freqDex_0 = maxIndex(freqs_0);
// Calculate key such that 'E' would be mapped to the most common ciphertext character
// since 'E' is expected to be the most common plaintext character
int dkey_0 = freqDex_0 - 4;
// Make sure our key is non-negative
if (dkey_0 < 0) {
dkey_0 = dkey_0+26;
}
// Find second key
int[] freqs_1 = countOccurrencesOfLetters(in_1);
int freqDex_1 = maxIndex(freqs_1);
int dkey_1 = freqDex_1 - 4;
if (freqDex_1 < 4) {
dkey_1 = dkey_1+26;
}
CaesarCipherTwoKeys cctk = new CaesarCipherTwoKeys(dkey_0, dkey_1);
return cctk.decrypt(input);
}
}
I'd like to implement the changes here:
public void simplebreaker()
{
FileResource fr = new FileResource();
String encrypted = fr.asString();
BreakCaesarThree bct = new BreakCaesarThree();
String broken = bct.decrypt(encrypted);
System.out.println("Keys found: " + bct.dkey_0 + ", " + bct.dkey_1 + "\n" + broken);
}
and here:
public void simpleTests()
{
int key1 = 17;
int key2 = 3;
FileResource fr = new FileResource();
String message = fr.asString();
CaesarCipherTwoKeys cctk = new CaesarCipherTwoKeys(key1, key2);
String encrypted = cctk.encrypt(message);
System.out.println(encrypted);
String decrypted = cctk.decrypt(encrypted);
System.out.println(decrypted);
BreakCaesarThree bct = new BreakCaesarThree();
String broken = bct.decrypt(encrypted);
System.out.println("Keys found: " + bct.dkey_0 + ", " + bct.dkey_1 + "\n" + broken);

Related

issue with Method returning the MD5 hash of a string in Java

Im an old Java student. Trying to create a method that returns a string variable with the value of a MD5 hash of any string.
Im getting an exception when compiling... "cannot find symbol"
public static String hash(String magicString){
try{
String hash = null;
byte[] arrayOfByte = MessageDigest.getInstance("MD5").digest(magicString.getBytes("UTF-8"));
for (int i = 0; i < arrayOfByte.length; i++) {
String string = Integer.toHexString(arrayOfByte[i]);
if (string.length() == 1) {
string = "0" + string;
}
string = string.substring(string.length() - 2);
hash = hash + string;
}
}catch (java.security.NoSuchAlgorithmException e){System.err.println("\nCaught Exception: " + e.getMessage()+ "\n\nMmm.. \n");
}return hash;
}
..thanks
Can not find symbol means that there is a problem in your Java source code
You have to declare the hash variable outside the try catch block
public static String hash(String magicString) throws UnsupportedEncodingException {
String hash = null;
try {
byte[] arrayOfByte = MessageDigest.getInstance("MD5").digest(magicString.getBytes("UTF-8"));
for (int i = 0; i < arrayOfByte.length; i++) {
String string = Integer.toHexString(arrayOfByte[i]);
if (string.length() == 1) {
string = "0" + string;
}
string = string.substring(string.length() - 2);
hash = hash + string;
}
} catch (java.security.NoSuchAlgorithmException e) {
System.err.println("\nCaught Exception: " + e.getMessage() + "\n\nMmm.. \n");
}
return hash;
}

Issue in parsing TLV data in java, how to get value,length

I have tried many sample codes to parse APDU response to TLV format.
I am able to parse it properly if the response length is less but facing issue if length is more(how calculate length of a tag without any libraries)
NOTE: I am using predefined tags in Constants
code:
private HashMap<String, String> parseTLV(String apduResponse) {
HashMap<String, String> tagValue = new HashMap<>();
String remainingApdu = apduResponse.replaceAll(" ", "");
if (remainingApdu.endsWith(ResponseTags._SUCCESS_STATUSWORDS)) {
remainingApdu = remainingApdu.substring(0, remainingApdu.length() - 4);
}
while (remainingApdu != null && remainingApdu.length() > 2) {
remainingApdu = addTagValue(tagValue, remainingApdu);
}
return tagValue;
}
addTagValue method
private String addTagValue(HashMap<String, String> tagValue, String apduResponse) {
String tag = "";
String length = "";
String value = "";
int tagLen = 0;
if (tagUtils.isValidTag(apduResponse.substring(0, 2))) {
tagLen = readTagLength(apduResponse.substring(3));
// tagLen = 2;
tag = apduResponse.substring(0, 2);
} else if (tagUtils.isValidTag(apduResponse.substring(0, 4))) {
tagLen = 4;
tag = apduResponse.substring(0, 4);
} else {
return "";
}
Log.e("TAG_LEN","tag: "+tag+"taglen: "+tagLen);
if (tagUtils.shouldCheckValueFor(tag)) {
length = apduResponse.substring(tagLen, tagLen + 2);
int len = tagUtils.hexToDecimal(length);
value = apduResponse.substring(tagLen + 2, (len * 2) + tagLen + 2);
tagValue.put(tag, value);
if (ResponseTags.getRespTagsmap().containsKey(tag)) {
//logData = logData + "\nKEY:" + tag + " TAG:" + ResponseTags.getRespTagsmap().get(tag)/* + " VALUE:" + value + "\n "*/;
}
if (tagUtils.isTemplateTag(tag)) {
// logData = logData + "\n\t-->";
return addTagValue(tagValue, value) + apduResponse.substring(tag.length() + value.length() + length.length());
} else {
return apduResponse.substring(tag.length() + value.length() + length.length());
}
} else {
value = apduResponse.substring(2, 4);
tagValue.put(tag, value);
// logData = logData + "\n\t\tKEY:" + tag + " TAG:" + ResponseTags.getRespTagsmap().get(tag) /*+ " VALUE:" + value + "\n "*/;
return apduResponse.substring(tag.length() + value.length() + length.length());
}
}
readTagLength :
private int readTagLength(String apduResponse) {
int len_bytes = 0;
if (apduResponse.length() > 2) {
len_bytes = (apduResponse.length()) / 2;
}
Log.e("tlv length:", "bytes:" + len_bytes);
if (len_bytes < 128) {
return 2;
} else if (len_bytes > 127 && len_bytes < 255) {
return 4;
} else {
return 6;
}
}
I cannot able to get length properly for few cards(if apdu response is long)
Please help
First be sure the input data is proper before you go into the code. Take the full data and try it on https://www.emvlab.org/tlvutils/ .
Once its confirmed the data is proper, go through in EMV 4.3 Book 3,
Annex B Rules for BER-TLV Data Objects sections B1, B2, B3 - with utmost attention.
If you follow this precisely, then you wouldn't need to store a static list of tags; will save time in future.
Below sample has an assumption that TLV array is ending with special 0x00 tag but for sure you can ignore it.
Pojo class :
public class Tlv {
private short tag;
private byte[] value;
public Tlv(short tag) {
this.tag = tag;
}
public short getTag() {
return tag;
}
public byte[] getValue() {
return value;
}
public void setValue(byte[] valueBytes) {
this.value = valueBytes;
}
}
Utility method :
public static Map<Byte, Tlv> parse(ByteBuffer bb) throws TlvException {
Map<Byte, Tlv> tlvs = null;
tlvs = new HashMap<Byte, Tlv>();
try {
while (bb.remaining() > 0) {
byte tag = bb.get();
if(tag == 0x00)
continue;
int length = bb.get();
byte[] value = new byte[length];
bb.get(value, 0, length);
Tlv tlv = new Tlv(tag);
tlv.setValue(value);
tlvs.put(tag, tlv);
}
} catch (IndexOutOfBoundsException e) {
throw new TlvException("Malformed TLV part: " + bb.toString() + ".", e);
}
return tlvs;
}

How to remove letter in space for One Time Pad cipher?

I have found this code somewhere on the web for reference yet this bothers me. The result is correct but somehow there is something wrong with the process.
import java.io.*;
import java.util.*;
import java.util.Scanner;
public class onetime{
public static void main(String[] args){
System.out.println("Type Message: " );
Scanner sc = new Scanner(System.in);
String text = sc.nextLine();
String key = RandomAlpha(text.length());
String enc = OTPEncryption(text,key);
System.out.println("Plaintext : " +text);
System.out.println("Key: "+key);
System.out.println("Encrypted : "+enc);
System.out.println("Decrypted : "+OTPDecryption(enc,key));
}
public static String RandomAlpha(int len){
Random r = new Random();
String key = "";
for(int x=0;x<len;x++)
key = key + (char) (r.nextInt(26) + 'A');
return key;
}
public static String OTPEncryption(String text,String key){
String alphaU = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String alphaL = "abcdefghijklmnopqrstuvwxyz";
int len = text.length();
String sb = "";
for(int x=0;x<len;x++){
char get = text.charAt(x);
char keyget = key.charAt(x);
if(Character.isUpperCase(get)){
int index = alphaU.indexOf(get);
int keydex = alphaU.indexOf(Character.toUpperCase(keyget));
int total = (index + keydex) % 26;
sb = sb+ alphaU.charAt(total);
}
else if(Character.isLowerCase(get)){
int index = alphaL.indexOf(get);
int keydex = alphaU.indexOf(Character.toLowerCase(keyget));
int total = (index + keydex) % 26;
sb = sb+ alphaL.charAt(total);
}
else{
sb = sb + get;
}
}
return sb;
}
public static String OTPDecryption(String text,String key){
String alphaU = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String alphaL = "abcdefghijklmnopqrstuvwxyz";
int len = text.length();
String sb = "";
for(int x=0;x<len;x++){
char get = text.charAt(x);
char keyget = key.charAt(x);
if(Character.isUpperCase(get)){
int index = alphaU.indexOf(get);
int keydex = alphaU.indexOf(Character.toUpperCase(keyget));
int total = (index - keydex) % 26;
total = (total<0)? total + 26 : total;
sb = sb+ alphaU.charAt(total);
}
else if(Character.isLowerCase(get)){
int index = alphaL.indexOf(get);
int keydex = alphaU.indexOf(Character.toLowerCase(keyget));
int total = (index - keydex) % 26;
total = (total<0)? total + 26 : total;
sb = sb+ alphaL.charAt(total);
}
else{
sb = sb + get;
}
}
return sb;
}
}
Output
Plain Text: help me
Key: QMMNQAB
Encrypted: gdko ld
Decrypt: help me
so as you can here in the output the second 'Q' of the key isn't supposed to be there because it's supposed to be a space. How can I remove it?
Your answer is highly appreciated thank you :)

base64 decoding to UTF-8, one character not displaying correctly

I am trying to decode a string from base64 to UTF-8 for an assignment.
Not having programmed Java for a while I am probably not using the most efficient method, however I managed to implement a function working 99% correctly.
Decoding the example string in Base64: VGhpcyBpcyBhbiBBcnhhbiBzYW1wbGUgc3RyaW5nIHRoYXQgc2hvdWxkIGJlIGVhc2lseSBkZWNvZGVkIGZyb20gYmFzZTY0LiAgSXQgaW5jbHVkZXMgYSBudW1iZXIgb2YgVVRGOCBjaGFyYWN0ZXJzIHN1Y2ggYXMgdGhlIPEsIOksIOgsIOcgYW5kICYjOTYwOyBjaGFyYWN0ZXJzLg==
Results in:
This is an Arxan sample string that should be easily decoded from base64. It includes a number of UTF8 characters such as the ñ, é, è, ç and &#960 characters.
However, in the place of the &#960 should be the π symbol being outputted.
Note that I removed the ; after &#960 in here as it seems Stackoverflow automatically corrected it to π
I have tried many things such as creating a byte array and printing that, but still not working.
I am using Eclipse, can it be that just the output there displays incorrectly?
Does somebody have a suggestion to get this to work?
Thanks,
Vincent
Here is my code:
package base64;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
public class Base64 {
public static void main(String[] args) {
//Input strings
String base64 = "VGhpcyBpcyBhbiBBcnhhbiBzYW1wbGUgc3RyaW5nIHRoYXQgc2hvdWxkIGJlIGVhc2lseSBkZWNvZGVkIGZyb20gYmFzZTY0LiAgSXQgaW5jbHVkZXMgYSBudW1iZXIgb2YgVVRGOCBjaGFyYWN0ZXJzIHN1Y2ggYXMgdGhlIPEsIOksIOgsIOcgYW5kICYjOTYwOyBjaGFyYWN0ZXJzLg==";
//String base64 = "YW55IGNhcm5hbCBwbGVhc3U=";
String utf8 = "any carnal pleas";
//Base64 to UTF8
System.out.println("Base64 conversion to UTF8");
System.out.println("-------------------------");
System.out.println("Input base64-string: " + base64);
System.out.println("Output UTF8-string: " + stringFromBase64(base64));
System.out.println();
//UTF8 to Base64
System.out.println("UTF8 conversion to base64");
System.out.println("-------------------------");
System.out.println("Input UTF8-string: " + utf8);
System.out.println("Output base64-string: " + stringToBase64(utf8));
System.out.println();
System.out.println("Pi is π");
}
public static String stringFromBase64(String base64) {
StringBuilder binary = new StringBuilder();
int countPadding = countPadding(base64); //count number of padding symbols in source string
//System.out.println("No of *=* in the input is : " + countPadding);
//System.out.println(base64);
for(int i=0; i<(base64.length()-countPadding); i++)
{
int base64Value = fromBase64(String.valueOf(base64.charAt(i))); //convert Base64 character to Int
String base64Binary = Integer.toBinaryString(base64Value); //convert Int to Binary string
StringBuilder base64BinaryCopy = new StringBuilder(); //debugging
if (base64Binary.length()<6) //adds required zeros to make 6 bit string
{
for (int j=base64Binary.length();j<6;j++){
binary.append("0");
base64BinaryCopy.append("0"); //debugging
}
base64BinaryCopy.append(base64Binary); // debugging
} else // debugging
{
base64BinaryCopy.append(base64Binary); //debugging
} // debugging
//System.out.println(base64.charAt(i) + " = " + base64Value + " = " + base64BinaryCopy); //debugging
binary.append(base64Binary);
}
//System.out.println(binary);
//System.out.println(binary.length());
StringBuilder utf8String = new StringBuilder();
for (int bytenum=0;bytenum<(binary.length()/8);bytenum++) //parse string Byte-by-Byte
{
StringBuilder utf8Bit = new StringBuilder();
for (int bitnum=0;bitnum<8;bitnum++){
utf8Bit.append(binary.charAt(bitnum+(bytenum*8)));
}
char utf8Char = (char) Integer.parseInt(utf8Bit.toString(), 2); //Byte to utf8 char
utf8String.append(String.valueOf(utf8Char)); //utf8 char to string and append to final utf8-string
//System.out.println(utf8Bit + " = " + Integer.parseInt(utf8Bit.toString(), 2) + " = " + utf8Char + " = " + utf8String); //debugging
}
return utf8String.toString();
}
public static String stringToBase64(String utf8) {
StringBuilder binary = new StringBuilder();
String paddingString = "";
String paddingSymbols = "";
for(int i=0; i<(utf8.length()); i++)
{
int utf8Value = utf8.charAt(i); //convert utf8 character to Int
String utf8Binary = Integer.toBinaryString(utf8Value); //convert Int to Binary string
StringBuilder utf8BinaryCopy = new StringBuilder(); //debugging
if (utf8Binary.length()<8) //adds required zeros to make 8 bit string
{
for (int j=utf8Binary.length();j<8;j++){
binary.append("0");
utf8BinaryCopy.append("0"); //debugging
}
utf8BinaryCopy.append(utf8Binary); // debugging
} else // debugging
{
utf8BinaryCopy.append(utf8Binary); //debugging
} // debugging
//System.out.println(utf8.charAt(i) + " = " + utf8Value + " = " + utf8BinaryCopy);
binary.append(utf8Binary);
}
if ((binary.length() % 6) == 2) {
paddingString = "0000"; //add 4 padding zeroes
paddingSymbols = "==";
} else if ((binary.length() % 6) == 4) {
paddingString = "00"; //add 2 padding zeroes
paddingSymbols = "=";
}
binary.append(paddingString); //add padding zeroes
//System.out.println(binary);
//System.out.println(binary.length());
StringBuilder base64String = new StringBuilder();
for (int bytenum=0;bytenum<(binary.length()/6);bytenum++) //parse string Byte-by-Byte per 6 bits
{
StringBuilder base64Bit = new StringBuilder();
for (int bitnum=0;bitnum<6;bitnum++){
base64Bit.append(binary.charAt(bitnum+(bytenum*6)));
}
int base64Int = Integer.parseInt(base64Bit.toString(), 2); //Byte to Int
char base64Char = toBase64(base64Int); //Int to Base64 char
base64String.append(String.valueOf(base64Char)); //base64 char to string and append to final Base64-string
//System.out.println(base64Bit + " = " + base64Int + " = " + base64Char + " = " + base64String); //debugging
}
base64String.append(paddingSymbols); //add padding ==
return base64String.toString();
}
public static char toBase64(int a) { //converts integer to corresponding base64 char
String charBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//charBase64 = new char[]{'A','B','C','D','E','F','G','H','I','J','K','L','M','N'};
return charBase64.charAt(a);
}
public static int fromBase64(String x) { //converts base64 string to corresponding integer
String charBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
return charBase64.indexOf(x);
}
public static int countPadding(String countPadding) { //counts the number of padding symbols in base64 input string
int index = countPadding.indexOf("=");
int count = 0;
while (index != -1) {
count++;
countPadding = countPadding.substring(index + 1);
index = countPadding.indexOf("=");
}
return count;
}
}
UTF8 is a character encoding that transforms a given char to 1, 2 or more bytes. Your code assumes that each byte should be transformed to a character. That works fine for ASCII characters such as a, b, c that are indeed transformed to a single byte by UTF8, but it doesn't work for characters like PI, which are transformed to a multi-byte sequence.
Your algorithm is awfully inefficient, and I would just ditch it and use a ready-to-use ecnoder/decoder. The JDK 8 comes with one. Guava and commons-codec also do. Your code should be as simple as
String base64EncodedByteArray = "....";
byte[] decodedByteArray = decoder.decode(base64EncodedByteArray);
String asString = new String(decodedByteArray, StandardCharSets.UTF_8);
or, for the other direction:
String someString = "VGhpcyBpcyBhb...";
byte[] asByteArray = someString.getBytes(StandardCharSets.UTF_8);
String base64EncodedByteArray = encoder.encode(asBytArray);

JAVA to Perl - port XOR encryptor class

I have the folowing JAVA class of a XOR "encryption" class:
import java.io.PrintStream;
public class Encryptor
{
private static final String m_strPrivateKey = "4p0L#r1$";
public Encryptor()
{
}
public static String encrypt(String pass)
{
String strTarget = XORString(pass);
strTarget = StringToHex(strTarget);
return strTarget;
}
public static String decrypt(String pass)
{
String strTarget = HexToString(pass);
strTarget = XORString(strTarget);
return strTarget;
}
private static String GetKeyForLength(int nLength)
{
int nKeyLen = "4p0L#r1$".length();
int nRepeats = nLength / nKeyLen + 1;
String strResult = "";
for(int i = 0; i < nRepeats; i++)
{
strResult = strResult + "4p0L#r1$";
}
return strResult.substring(0, nLength);
}
private static String HexToString(String str)
{
StringBuffer sb = new StringBuffer();
char buffDigit[] = new char[4];
buffDigit[0] = '0';
buffDigit[1] = 'x';
int length = str.length() / 2;
byte bytes[] = new byte[length];
for(int i = 0; i < length; i++)
{
buffDigit[2] = str.charAt(i * 2);
buffDigit[3] = str.charAt(i * 2 + 1);
Integer b = Integer.decode(new String(buffDigit));
bytes[i] = (byte)b.intValue();
}
return new String(bytes);
}
private static String XORString(String strTarget)
{
int nTargetLen = strTarget.length();
String strPaddedKey = GetKeyForLength(nTargetLen);
String strResult = "";
byte bytes[] = new byte[nTargetLen];
for(int i = 0; i < nTargetLen; i++)
{
int b = strTarget.charAt(i) ^ strPaddedKey.charAt(i);
bytes[i] = (byte)b;
}
String result = new String(bytes);
return result;
}
private static String StringToHex(String strInput)
{
StringBuffer hex = new StringBuffer();
int nLen = strInput.length();
for(int i = 0; i < nLen; i++)
{
char ch = strInput.charAt(i);
int b = ch;
String hexStr = Integer.toHexString(b);
if(hexStr.length() == 1)
{
hex.append("0");
}
hex.append(Integer.toHexString(b));
}
return hex.toString();
}
public static void main(String args[])
{
if(args.length < 1)
{
System.err.println("Missing password!");
System.exit(-1);
}
String pass = args[0];
String pass2 = encrypt(pass);
System.out.println("Encrypted: " + pass2);
pass2 = decrypt(pass2);
System.out.println("Decrypted: " + pass2);
if(!pass.equals(pass2))
{
System.out.println("Test Failed!");
System.exit(-1);
}
}
}
I tried to port it to Perl like this:
#!/usr/bin/perl
use strict;
use warnings;
my $pass = shift || die "Missing password!\n";
my $pass2 = encrypt($pass);
print "Encrypted: $pass2\n";
$pass2 = decrypt($pass2);
print "Decrypted: $pass2\n";
if ($pass ne $pass2) {
print "Test Failed!\n";
exit(-1);
}
sub encrypt {
my $pass = shift;
my $strTarget = XORString($pass);
$strTarget = StringToHex($strTarget);
return $strTarget;
}
sub decrypt {
my $pass = shift;
my $strTarget = HexToString($pass);
$strTarget = XORString($strTarget);
return $strTarget;
}
sub GetKeyForLength {
my $nLength = shift;
my $nKeyLen = length '4p0L#r1$';
my $nRepeats = $nLength / $nKeyLen + 1;
my $strResult = '4p0L#r1$' x $nRepeats;
return substr $strResult, 0, $nLength;
}
sub HexToString {
my $str = shift;
my #bytes;
while ($str =~ s/^(..)//) {
my $b = eval("0x$1");
push #bytes, chr sprintf("%d", $b);
}
return join "", #bytes;
}
sub XORString {
my $strTarget = shift;
my $nTargetLen = length $strTarget;
my $strPaddedKey = GetKeyForLength($nTargetLen);
my #bytes;
while ($strTarget) {
my $b = (chop $strTarget) ^ (chop $strPaddedKey);
unshift #bytes, $b;
}
return join "", #bytes;
}
sub StringToHex {
my $strInput = shift;
my $hex = "";
for my $ch (split //, $strInput) {
$hex .= sprintf("%02x", ord $ch);
}
return $hex;
}
Code seems ok but the problem is the JAVA class outputs different results than the Perl code.
In JAVA I have the plain-text passsword
mentos
and it is encoded as
&4\=80CHB'
What should I do to my Perl script to get the same result? Where I do wrong?
Another two examples: plain-text
07ch4ssw3bby
is encoded as:
,#(0\=DM.'# '8WQ2T
(note the space after #)
Last example, plain-text:
conf75
encoded as:
&7]P0G-#!
Thanks for help!
Ended up with this, thanks to Joni Salonen:
#!/usr/bin/perl
# XOR password decoder
# Greets: Joni Salonen # stackoverflow.com
$key = pack("H*","3cb37efae7f4f376ebbd76cd");
print "Enter string to decode: ";
$str=<STDIN>;chomp $str; $str =~ s/\\//g;
$dec = decode($str);
print "Decoded string value: $dec\n";
sub decode{ #Sub to decode
#subvar=#_;
my $sqlstr = $subvar[0];
$cipher = unpack("u", $sqlstr);
$plain = $cipher^$key;
return substr($plain, 0, length($cipher));
}
My only and last problem is that when a "\" is found (actually "\\" as one escaped the real character) the decryption goes wrong :-\
Example encoded string:
"(4\\4XB\:7"G#, "
(I escaped it with double-quotes, last characters of the string is a space, it should decode to
"ovFsB6mu"
Update: thanks to Joni Salonen, I have 100% working final version:
#!/usr/bin/perl
# XOR password decoder
# Greets: Joni Salonen # stackoverflow.com
$key = pack("H*","3cb37efae7f4f376ebbd76cd");
print "Enter string to decode: ";
$str=<STDIN>;chomp $str; $str =~s/\\(.)/$1/g;
$dec = decode($str);
print "Decoded string value: $dec\n";
sub decode{ #Sub to decode
#subvar=#_;
my $sqlstr = $subvar[0];
$cipher = unpack("u", $sqlstr);
$plain = $cipher^$key;
return substr($plain, 0, length($cipher));
}
Your encryption loop skips the first character of $strTarget if it happens to be '0'. You could compare it against an empty string instead of checking if it's "true":
while ($strTarget ne '') {
my $b = (chop $strTarget) ^ (chop $strPaddedKey);
unshift #bytes, $b;
}
Update: This program decrypts your strings:
use feature ':5.10';
$key = pack("H*","3cb37efae7f4f376ebbd76cd");
say decrypt("&4\=80CHB'"); # mentos
say decrypt(",#(0\=DM.'# '8WQ2T"); # 07ch4ssw3bby
say decrypt("&7]P0G-#!"); # conf75
sub decrypt {
$in = shift;
$cipher = unpack("u", $in);
$plain = $cipher^$key;
return substr($plain, 0, length($cipher));
}

Categories