
Acceleration cipher: we study the accelerometer of an Android device using the example of the NeoQUEST-2019 task

The accelerometer - aka G-sensor - is one of the most common sensors today. You can meet it in almost every modern gadget. The accelerometer performs a fairly simple task - it measures the acceleration of the device. Let's see how he does it - let's analyze the mechanisms of the Android API sensors using the example of task No. 7 from the online stage of NeoQUEST-2019.
According to legend, we were given 2 files: 7.apk and 7.txt . The following conclusions can be drawn from the text of the task (and all tasks are still available here ): 7.apk - an encryption program that somehow uses the accelerometer settings of the device; 7.txt - cryptogram generated by the encoder. The following is written in it:
[1749054104147639] [2.07154922] [10.001905] [4.5387093] [1749056073889025] [5.7193284] [8.221763] [0.01391537] [1749058029180773] [4.684068] [12.05614] [0.0377285] [174907294294296296904294904294904294294904294294904294294904294294904294904294294904294904294294904294294904294904294904294904294904294904294904294904294904294904294904294904294904294904294904294904294294904294904294904294904294294OF thensoprodivaniyahs of the Soviet Union. ] [4.4682417] [7.512769] [6.037215] [1749067640096818] [1.0396843] [8.798672] [4.9335976] [1749070016073380] [2.3173676] [10.180047] [4.948362] [1749072343679582] [126060] 2.48394698] [10.834006] [6.306282] [1749075827770391] [0.2795044] [13.279829] [0.19391555]
We see that the text is a repeating group of 4 values, one of which is integer, and the remaining 3 are floating-point numbers. For convenience, we will arrange them in separate lines:
[1749054104147639] [- 2.07154922] [10.001905] [4.5387093]
[1749056073889025] [5.7193284] [8.221763] [0.01391537]
[1749058029180773] [- 4.684068] [12.05614] [0.0377285]
[1749060105291613] [4.6900544] [6.9307165] [- 4.7094293]
[1749062123327502] [4.4682417] [7.512769] [6.037215]
[1749067640096818] [1.0396843] [8.798672] [- 4.9335976 ]
[1749070016073380] [- 2.3173676] [10.180047] [4.948362]
[1749072343679582] [- 4.3660607] [12.218135] [0.5312999]
[1749073674459611] [-
2.48394698] [10.834006] [79190929292929929] [-0.19391555]
The cryptogram format was sorted out, but what these values are is not known. Some parameters of the accelerometer of the device, without any specifics. And let's go to the Android developers site and see what the accelerometer can show in general.
We see the following description:

We figured out what the floating point parameters are responsible for - this is the acceleration of the device along the X, Y, and Z axes. But how to understand which axis each of them is responsible for? It's time to launch the application. It looks like this:

There are 2 options for determining application behavior: decompiling .apk and analyzing the resulting values. Next, we consider the second method and give the insertion of the decompiled code that is responsible for the considered actions of the application.
The cryptogram contains positive and negative values (we know that these are accelerations on different axes), so we can make an assumption: if the device's tilt vectors along the axis are opposite, then the acceleration values will be approximately equal in absolute value, and the difference will only be in sign.
The following is a code listing for storing acceleration information:
public class MotionSnapshot
{
public final float angle_alpha;
public final float angle_beta;
public final float angle_gamma;
public final long event_time;
...
}
Based on these considerations, we face the following tasks:
- Determine what value in the cryptogram corresponds to the slope of the device
- Define deviation pattern
- To each digit to associate a deviation pattern for decryption
The first 2 tasks will be performed in parallel. On the phone we can test 2 types of tilt:
- From myself / to myself
- Left / right

The code responsible for handling events from the accelerometer
public class SensorListener implements SensorEventListener
{
private MotionTrace Trace;
public SensorListener(MotionTrace trace, MainActivity activity)
{
Trace = trace;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
@Override
public void onSensorChanged(SensorEvent event)
{
Trace.addSnaphot(new MotionSnapshot(event.values, event.timestamp));
}
}
The code responsible for generating the slope of the device at the click of a button
public class MotionTrace
{
private ArrayList Deltas;
private long Length;
private MotionSnapshot LastSnapshot;
public MotionTrace(long len)
{
LastSnapshot = new MotionSnapshot(0,0,0,0);
Deltas = new ArrayList<>();
Length = len;
}
public void addSnaphot(MotionSnapshot snapshot)
{
if (Deltas.size() >= Length)
{
Deltas.remove(0);
}
MotionSnapshot delta = new MotionSnapshot(0,0,0,0);
if (Deltas.size() > 0)
{
delta = snapshot;
}
Deltas.add(delta);
}
public ArrayList getDeltas()
{
return new ArrayList<>(Deltas);
}
}
The code responsible for generating the cryptogram
public void SaveCiphertext()
{
Log.d(Config.MAIN_TAG, "SAVING - {{" + Ciphertext + "}}");
try
{
File root = new File(Environment.getExternalStorageDirectory(), Config.DIRNAME);
if (!root.exists())
{
Log.d(Config.MAIN_TAG, "Creating directory - [" + root + "]");
if (!root.mkdirs())
{
Log.d(Config.MAIN_TAG, "Error creating directory");
}
}
File out_file = new File(root, Config.FILENAME);
Log.d(Config.MAIN_TAG, "Out - [" + out_file + "]");
PrintWriter writer = new PrintWriter(out_file, "UTF-8");
writer.println(Ciphertext);
writer.close();
Toast.makeText(this, "Saved to - [" + out_file + "]", Toast.LENGTH_LONG).show();
}
catch (IOException ex)
{
Toast.makeText(this, "Error saving data", Toast.LENGTH_SHORT).show();
}
Ciphertext = "";
}
Let's start in order. To test the slopes of the first type, we select the numbers 2 and 8. Click on each 3 times with increasing effort. We
get the
following result: [2687418463227102] [- 0.23700714] [10.764615] [- 0.9759079] [2687419411042043] [- 3.5834892] [13.591138] [- 1.7036858] [2687420383026907] [- 5.575793] [13.53324244] [- 1.375328428] [13.53324288] [13.53324288] 0.6850295] [6.0002656] [0.5568123] [2687422317256542] [4.1720495] [1.8675026] [1.545407] [2687423250514599] [7.9689393] [- 3.600097] [0.33846742]
Excellent, the differences in the 2 parameters are visible to the naked eye. Let's start filling out the template.
We represent the template in the form of ranges of values of the corresponding fields in the cryptogram line. We mark with a question mark what we do not yet know.
[? ]
[(<0) - deviation from oneself; (> 0) - self-rejection]
[?]
[?]
Similarly, we will carry out tests with buttons 4 and 6. Results:
[2688019191605386] [1.7270225] [9.541045] [0.0397171]
[2688020247971353] [1.0615791] [9.794326] [4.9135437]
[2688021887957875] [1.0974716] [7.5535636] [7.8307548]
[2688023749896352] [1.3328063]
[9.43923] [- 0.27600938]
[2688024849688832] [1.1357567] [9.9313135] [- 2.4410335258268338258268338258268338258268338258268338258 ]
Update the template taking into account the investigated pattern:
[? ]
[(<0) - deviation from oneself; (> 0) - deviation to itself]
[?]
[(<0) - deviation to the right; (> 0) - deviation to the left]
Obviously, the third value is the up / down deviation, as this is the only remaining vector. And we don’t really need to check it, because for the unambiguous determination of the pressed button, we already have the well-known template.
Now we will create a template for each digit on the keyboard, based on the position of the buttons and the developed template (* - the parameter does not interest us):
1 - [*] [<0] [*] [> 0]
2 - [*] [<0] [*] [close to 0]
3 - [*] [<0] [*] [<0]
4 - [*] [] [*] []
5 - [*] [close to 0] [*] [ close to 0]
6 - [*] [close to 0] [*] [<0]
7 - [*] [> 0] [*] [> 0]
8 - [*] [> 0] [*] [ close to 0]
9 - [*] [> 0] [*] [<0]
0 - [*] [> 0] [*] [close to 0]
As can be seen from the figure, buttons 8 and 0 have the same parameters, so their decryption can be ambiguous - when encountering such a combination in a cryptogram, you should try both options. Now we apply the obtained templates to the cryptogram, and we get 2 answers: 1029761235 and 1829761235, of which 1829761235 is true . Assignment completed!
Very soon - on June 26 - the NeoQUEST 2019 Face-to-Face Competition will take place! Hurry up to register on the event website. In the near future habrastatya will be released with the announcement of the program, do not miss!