Is this encryption function reversible? - java

I'm currently working on a small challenge, trying to figure out how an unnamed encryption algorithm works. The original algorithm looks like this:
public final String a(byte[] original)
{
this.a = original.length;
byte[] solution = new byte[8];
int i = 0;
int base = 13;
for (int si = 0; si < 8; si++)
{
for (int oi = 0; oi < a; oi++)
{
byte current = original[oi];
solution[i] = ((byte)(solution[i] + (current ^ base)));
base = (base ^ i) + solution[i];
i = (i + 1) % 8;
}
}
char[] result = new char[8];
for (int n = 0; n < 8; n++) {
result[n] = ((char)((solution[n] & 0x3F) + 48));
}
return String.valueOf(result);
}
So every string that gets passed to this function as a byte[] array will be encoded into a 8-char somewhat cryptic text. I've found out other things about this:
The encoded characters in the char[] result always have literals with values between 48 and 111 (0x3F + 48).
When decoding, the first step would be subtracting 48 and then undo the & operation. Since 0x3F equals the binary representation 111111, the value of the original byte is one of 4 possibilities:
00xxxxxx: the missing 2 bits were both zero.
01xxxxxx: the lower addressed bit of both was one.
10xxxxxx: the higher addressed bit of both was one.
11xxxxxx: both of them were one.
Meaning, it could be one of four characters. I initially thought about reversing the algorithm, but I'm asking you if this is even possible for this kind of algorithm. I tried it and came this far:
public static String b(String encrypted) {
byte[][] matrix = new byte[4][20];
byte[] word = encrypted.getBytes();
for(int i = 0; i < 4; i++) {
for(int j = 0; j < word.length; j++) {
byte tmp = (byte)(word[i] - 48);
matrix[i][j] = (byte)(tmp + i);
}
}
}
I currently subtract 48 and insert all 4 possibilities into a 2D-array. But im stuck solving the nested for loop, especially the variables i and base are hard to find out. The only information I have is the encrypted word and the fact that the original word was 20 literals long at MAX (Hence the [4][20] dimensions).
The encryption doesn't look familiar to me, which leaves me no options to look for the name of this algorithm.
If it is possible to reverse this algorithm, what would my next step be?

No, that obviously can't be reversible in the general case.
There are effectively 40 bits of information in the output (eight bytes, at 5 bits each -- & 0x1F limits each one to five bits). This means that there are only 240 possible outputs; there are far more possible inputs than that.
If there are some constraints on the input -- for instance, if its length is known to be short -- it might be possible to make some inferences about that. However, you haven't stated any constraints, so…

Related

Generating all words of length N from a given alphabet in Java

The cleanest way to generate all N - length words, with characters from a given alphabet , such that they must have in them a given character c.
If the length is 2, for an alphabet with this characters {a,b} , and the character is 'b' it should return a list like this:
ab , ba , bb
So far I am thinking of using nested loops, but it's not clean, or using similar methods to permutation , to generate them all by increment the least significant bit and wrapping around when reaching last character from alphabet.
EDIT:
ArrayList <String> data = new ArrayList <String>();
int iterations = (int) Math.pow(alfabet.length, N);
int pos [] = new int [N];
pos[N-1] = -1;
for (int i = 0 ; i < iterations;i++)
{
pos[N-1]++;
for (int j = N-1; j >= 0;j--)
{
if (pos[j] == alfabet.length)
{
pos[j] = 0;
pos[j-1] ++;
}
else break;
}
String word = "";
for (int j = 0 ; j < N; j++ )
{
word += alfabet[pos[j]];
}
int val = 0;
for (int j = 0 ; j < lst.length; j++)
{
if (word.contains(lst[j] + "")) val++;
}
if (val == lst.length) data.add(word);
}
return data;
This is the function i built, i made the alphabet static, for easier access through the code, and because i wont change it.
Improved on it a bit, and made it so that it doesnt check just a character, but a certain array of characters.
Would like a review of clarity, complexity or some things that i might have looked over.
Since you didn't provide any Java code, I won't either ;) I don't want to spoil your fun...
A short, somewhat fast, non-recursive solution in pseudocode (aka, Swift) to get you going:
let alphabet = ["a", "b", "c"]
let requiredChar = 2
func printAllWords() {
var word = [0, 0]
for _ in 0 ..< pow(alphabet.count, word.count) {
if word.contains(requiredChar) { print(word) }
for char in 0 ..< word.count {
word[char] = (word[char] + 1) % alphabet.count
if word[char] != 0 { break } // overflow
}
}
}
outputs the desired words:
ca
cb
ac
bc
cc
This should run in O(n.zⁿ) time complexity, where:
n is the word length;
and z the alphabet length.
To play around with this code, try this Swift sandbox.
Getting a working Java version out of this should be straightforward. A Kotlin version should be even easier... ;)

Generating all subsets using Gosper's Hack (Bankers sequence)

I have a method that generates all subsets of an array, what I want to try and implement is the same sort of method but doing it using binary. Gosper's Hack seems to be the best idea but I have no idea how to implement it. The code below works to generate all subsets.The subsets can be unknown (http://imgur.com/KXflVjq) this shows an output after a couple of seconds of running. Thanks for any advice
int m = prop.length;
int list = (1 << m);
for(long i = 1; i<list; i++) {
final List sub = new ArrayList<>();
for(long j=0; j<m; j++) {
if((i & (1<<j)) > 0) {
sub.add(j);
}
}
Collections.sort(sub);
System.out.println(sub);
}
EDIT: As I have not worded the question correctly, what I need as output is:
2 1 0
0 0 1 = 0
0 1 0 = 1
etc.
First, I'd like to note that it's not clear what exactly is it that you're trying to achieve; please consider clarifying the question. I'll assume that you'd like to generate all k-subsets of an n-set. The problem can be easily reduced to that of generating all k-subsets of {1,2,...,n} (i.e. it suffices to compute all k-subsets of indices).
An algorithm for generating k-subsets of an n-set
A while back I wrote this implementation of a method (which I rediscovered few years ago) for generating all k-subsets of an n-set. Hope it helps. The algorithm essentially visists all binary sequences of length n containing exactly k ones in a clever way (without going through all 2^n sequences); see the accompanying note describing the algorithm, which contains detailed description, pseudocode, and a small step-by-step example.
I think the time complexity is of the order O(k {n choose k}). I do not yet have a formal proof for this. (It is obvious that any algorithm will have to take Omega({n choose k}) time.)
The code in C:
#include <stdlib.h>
#include <stdio.h>
void subs(int n, int k);
int main(int argc, char **argv)
{
if(argc != 3) return 1;
int n, k;
n = atoi(argv[1]); k = atoi(argv[2]);
subs(n, k);
return 0;
}
void subs(int n, int k)
{
int *p = (int *)malloc(sizeof(int)*k);
int i, j, r;
for(i = 0; i < k; ++i) p[i] = i; // initialize our ``set''
// the algorithm
while(1)
{ // visit the current k-subset
for(i = 0; i < k; ++i)
printf("%d ", p[i]+1);
printf("\n");
if(p[0] == n-k) break; // if this is the last k-subset, we are done
for(i = k-1; i >= 0 && p[i]+k-i == n; --i); // find the right element
r = p[i]; ++p[i]; j = 2; // exchange them
for(++i; i < k; ++i, ++j) p[i] = r+j; // move them
}
free(p);
}
References
If this is not efficient enough, I highly recommend Knuth's Volume 4 of The Art of Comouter Programming, where he deals with the problem extensively. It's probably the best reference out there (and fairly recent!).
You might even be able to find a draft of the fascicle, TAOCP Volume 4 Fascicle 3, Generating All Combinations and Partitions (2005), vi+150pp. ISBN 0-201-85394-9, on Knuth's homepage (see his news for 2011 or so).

More effective method for Finding the most common character in a string

I created a method for finding the most common character in a string:
public static char getMax(String s) {
char maxappearchar = ' ';
int counter = 0;
int[] charcnt = new int[Character.MAX_VALUE + 1];
for (int i = 0 ; i < s.length() ; i++)
{
char ch = s.charAt(i);
// increment this character's cnt and compare it to our max.
charcnt[ch]++ ;
if (charcnt[ch] >= counter)
{
counter = charcnt[ch];
maxappearchar = ch;
}
}
System.out.println("the max char is " +maxappearchar + " and displayed " +counter+ " times");
return maxappearchar;
}
I am asking about different solutions for it:
solution 1 - Fastest code (is that my attached code?)
solution 2 - Most effective in terms of memory, reduced use of arrays and variables
I created my method using HashMap - is that more Suitable for solution 2? If so why? And what are the pros/cons?
Is the attached code is suitable for o Technique (o^ , o logn ... )? If so why?
The fastest way to do this will be to count occurrences of every character, then take the max value in the count array. If your string is long, you'll gain a decent speedup from not tracking the current max while looping over characters in the String.
See How to count frequency of characters in a string? for many other ideas about how to count frequencies.
If your Strings are mostly ASCII, a branch in the count loop to choose between an array for the low 128 char values, or a HashMap for the rest, should be worth it. The branch will predict well if your strings don't have non-ASCII characters. If there's a lot of alternating between ascii and non-ascii, the branch might hurt a bit, compared to using HashMap for everything.
public static char getMax(String s) {
char maxappearchar = ' ';
int counter = 0;
int[] ascii_count = new int[128]; // fast path for ASCII
HashMap<Character,Integer> nonascii_count = new HashMap<Character,Integer>();
for (int i = 0 ; i < s.length() ; i++)
{
char ch = s.charAt(i); // This does appear to be the recommended way to iterate over a String
// alternatively, iterate over 32bit Unicode codepoints, not UTF-16 chars, if that matters.
if (ch < 128) {
ascii_count[ch]++;
} else {
// some code to set or increment the nonascii_count[ch];
}
}
// loop over ascii_count and find the highest element
// loop over the keys in nonascii_count, and see if any of them are even higher.
return maxappearchar;
}
I didn't flesh out the code, since I don't do a lot of Java, so IDK if there's a container than can do the insert-1-or-increment operation more efficiently than a HashMap get and put pair. https://stackoverflow.com/a/6712620/224132 suggests Guava MultiSet<Character>, which looks good.
This may do better than your array of 2^16 ints. However, if you only ever touch the low 128 elements of this array, then most of the memory may never be touched. Allocated but untouched memory doesn't really hurt, or use up RAM / swap.
However, looping over all 65536 entries at the end means at least reading it, so the OS would have to soft pagefault it in and wire it up. And it will pollute caches. So actually, updating the max on every character might be a better choice. Microbenchmarks might show that iterating over the String, then looping over charcnt[Character.MAX_VALUE] wins, but that wouldn't account for the cache / TLB pollution of touching that much not-really-needed memory.
It is a fast algorithm using much space.
It does not cover full Unicode, there are code points (Unicode characters, ints) that need two chars.
Small optimizations still possible:
Making extra versions with byte[] and short[], depending on s.length().
Keeping the length() in a variable
for (int i = 0, n = s.length(); i < n; i++)
And yes a HashMap probably is the most "sensible" solution.
Now with java 8, you might turn to parallelism: using multiple cores. Not worth the effort.
int mostFrequentCodePoint = s.codePoints()
...
For frequency analysis in natural language, it may suffice to limit the string's length to 1000 or so.
public class HelloWorld {
public static void main(String[] args) {
String word = "Ferrari";
String mostUsedChar = "";
int count = 0;
String[] array = word.split("");
for (int i = 0; i < array.length; i++) {
int tempCount = 0;
for (int j = 0; j < array.length; j++)
{
if (array[i].equals(array[j])) {
tempCount++;
}
if (tempCount > count) {
count = tempCount;
mostUsedChar = array[i];
}
}
}
System.out.println(count + " Most Used Char: " + mostUsedChar);
}
}
Using the solution above returning a SimpleEntry<Character,Integer> (full implementation) for ASCII:
public static Map.Entry getMostCommonChar(String phrase) {
if (phrase == null || phrase.isEmpty()) {
throw new IllegalArgumentException("input phrase must have non-empty value.");
}
char maxchar = ' ';
int counter = 0;
int[] ascii_count = new int[Character.MAX_VALUE]; // fast path for ASCII
for (int i = 0; i < phrase.length(); i++) {
char ch = phrase.charAt(i); // This does appear to be the recommended way to iterate over a String
if (ascii_count[ch]++ >= counter) {
counter = ascii_count[ch];
maxchar = ch;
}
}
Map.Entry<Character,Integer> e = new AbstractMap.SimpleEntry<>(maxchar,counter);
System.out.println(e.getKey());
System.out.println(e.getValue());
return e;
}

What will this constructor look like?

public byte[] d
In this byte array, each byte represents a digits, where d[0] is the least significant digit, and a[d.length-1] is the most significant digit. For example, 543210 is stored as {0,1,2,3,4,5}. The most significant digit can't be a zero;
In the real implementation, this array should be private.
Constructor Detail: AdditionOnlyInt
public AdditionOnlyInt(java.lang.String a)
This is a constructor that construct an AdditionOnlyInt with value presented by the input string. For example, if input a = "00012340", this constructor will set the byte array to have value {0,4,3,2,1}. Note that the leading zeros in the input string should not be stored.
Parameters:a - is a string such as "00012340"
I do not know how to do this constructor does anyone?
I know its very wrong but I tried this
public AdditionOnlyInt(String number) {
int counter = number.length();
number.replace("0","");
data = new byte[number.length()];
int i = 0;
while(i<number.length()) {
data[i] = (byte)number.charAt(counter);
i++;
counter--;
}
}
and I do know converting to byte gives you different values.
You're in luck: only a handful of modifications need to be made to your program. You weren't entirely wrong. :)
First, these three statements are giving you fits:
int counter = number.length();
number.replace("0","");
data = new byte[number.length()];
You get a counter, which is the unbiased String (that is, with zeroes), which will undoubtedly be smaller than the String, without zeroes. You'd also be creating the array with the size of the unbiased list.
Well...it would be if your second statement did something. String is immutable, so anything that's done to modify it would only generate a new String, leaving the old one unmodified. That's fixable by this:
number = number.replace("0", "");
...but in reality, given your input set, it should be fixed by this:
number = String.valueOf(Integer.parseInt(number));
This way, you keep internal zeroes.
Now assuming that your byte[] is actually called data and not d, there's one little issue we have to fix: numbers in terms of a byte are quite large (that is, the character for '7' is 0x37, which is 55).
So we need to bias it. Whatever our byte number is, we need to subtract '0' from it; that is, we need to subtract 48 from it, to give us our correct value. I'll show you what that looks like in a moment.
Now, for your loop:
int i = 0;
while(i<number.length()) {
data[i] = (byte)number.charAt(counter);
i++;
counter--;
}
I'm not sold on the necessity of counter, so let's get rid of it. Now we'll use i from now on. Essentially, what this means is that we have to move charAt from the end of the String to the front of the String, placing the values into the array as such. What that (mostly) looks like is this:
data[i] = (byte) (number.charAt(number.length() - 1 - i);
Pay close attention here - we have to subtract 1 from the length right off the bat, since we don't have a place on the String that's exactly equal to its maximum length. We then subtract i from that, so we get the effect of moving backwards on the String.
That is, for a string of length 10 without zeroes, if we start at i = 0, we get the character at 10 - 1 - 0 = 9, or the last character.
Remember what I said about biasing the result of that, though? After you've got the data, be sure to subtract '0' from it.
data[i] = (byte) (number.charAt(number.length() - 1 - i) - '0';
And really, that's all there is to it. You mostly got it, except the iteration and sanitization was a bit wonky.
public AdditionOnlyInt(String input)
{
//remove trailing 0s
int relevStart = 0;
while(input.charAt(relevStart) == '0')
{
relevStart++;
}
String relevantTerms = input.substring(relevStart);
//flip the remaining chars
int length = relevantTerms.length();
data = new byte[length];
for(int iter = 0; iter < length; iter++)
{
data[iter] = (byte) (relevantTerms.charAt(length - iter - 1) - '0');
}
}
Hope this helps.
Step 1: Check whether its a number by using Integer value = Integer.valueOf(args);
Step 2: convert the Integer into a byte array by calling byte array[] = value.toString().getBytes();
Step 3: the byte array contains the value in forward fashion, So swapping all the values in the array will make the digit reverse as user requested.
for (int i = 0, j = array.length - 1; i < array.length / 2; i++, j--) {
byte temp = array[i];
array[i] = array[j];
array[j] = temp;
}
find the complete program below:
public class AdditionOnlyInt {
public static void main(String[] args) {
// TODO Auto-generated method stub
new AdditionOnlyInt("01010120");
}
public AdditionOnlyInt(String args) {
try {
Integer value = Integer.valueOf(args);
byte array[] = value.toString().getBytes();
for (int i = 0, j = array.length - 1; i < array.length / 2; i++, j--) {
byte temp = array[i];
array[i] = array[j];
array[j] = temp;
}
for (int i = 0; i < array.length; i++) {
System.out.print((char) array[i]);
}
} catch (Exception e) {
}
}
}

Convert a string of numbers to an array in Java, where each number is a different slot

Suppose I have a string of 123456789. I would like to split this string and each number goes in a different slot in the array. I can't use the split() method because there is nothing to split on. How would I accomplish this in Java.
int x=123456789;
char[] array = x.toString().toCharArray();
int intarray[] = new int[array.length];
for (int i = 0; i < array.length; i++) {
intarray[i] = Integer.parseInt(array[i]);
}
And after this you intarray will be array of your numbers.
If your integer can be negative too, you must take it's absolute value and make same operations, and after that multiple first array value by -1. But I guess, it's not needed.
EDIT:
I think, I don't understand your question properly. If you want to split only string, you must use this lines only. I wrote about integers,which might be helpful too.
string x="123456789";
char[] array = x.toCharArray();
If you're only dealing with non-negative integers, the toCharArray() method should be suitable for you. It gives you the string as an array.
The String class has a neat method for doing this, toCharArray().
You can use the following to avoid creating Strings.
long x = x;
ByteBuffer bb = ByteBuffer.allocate(18);
if (x == 0) {
bb.put((byte) 0);
} else {
while (x > 0) {
bb.put((byte) (x % 10));
x /= 10;
}
}
int len = bb.position();
byte[] digits = new byte[len];
for (int i = 0; i < len; i++)
digits[i] = bb.get(len - i - 1);
is it compelsory that the data will be of single digit ?If the data may come in multiple digits then it will not be possible to identify whether the numeric value is of single digit of multiple digit ?
e.g. if it is 12(twelve) then if all string is 512 then how will you identify whether to represent 512 as 5,1,2 or 5,12 ?
if it is fix that the numbers will be in single digits and non negetives then toCharArray() of String class will work for you

Categories