buttplugio / stpihkal

Repo deprecated, STPIHKAL moved to docs.buttplug.io repo
https://docs.buttplug.io/
93 stars 21 forks source link

Document Galaku Nebula Protocol #177

Open blackspherefollower opened 1 year ago

blackspherefollower commented 1 year ago

Note: there are multiple Galaku protocols

BLE Name: V415 Service UUID: 0x1000 Tx Characteristic UUID: 0x1001 Rx Characteristic UUID: 0x1002

This device has 2 features: "pump" (an oscillating stroker) and "intensity" (a vibe). Both have ranges 0-100 (0x00-0x64). The update command is checksumed and encrypted before being sent: see example code below:


public class HelloWorld{

private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for ( int j = 0; j < bytes.length; j++ ) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    public static byte[][] KeyTab = {new byte[]{0, 24, -104, -9, -91, 61, 13, 41, 37, 80, 68, 70}, new byte[]{0, 69, 110, 106, 111, 120, 32, 83, 45, 49, 46, 55}, new byte[]{0, 101, 120, 32, 84, 111, 121, 115, 10, -114, -99, -93}, new byte[]{0, -59, -42, -25, -8, 10, 50, 32, 111, 98, 13, 10}};

    public static int calcCheckSum(byte[] bArr, int i) {
        int i2 = 0;
        for (int i3 = 0; i3 < i; i3++) {
            i2 += bArr[i3];
        }
        return i2;
    }

    public static int getRandomNumber(int i, int i2) {
        return (int) (i + (Math.random() % ((i2 - i) + 1)));
    }

    public static byte GetTabKey(Byte b, int i) {
        return KeyTab[b.byteValue() & 3][i];
    }

    public static byte[] Encrypt(byte[] bArr) {
        byte[] bArr2 = new byte[12];
        byte b = bArr[0];
        bArr2[0] = b;
        for (int i = 1; i < 12; i++) {
            byte GetTabKey = GetTabKey(Byte.valueOf(bArr2[i - 1]), i);
            byte b2 = bArr[i];
            bArr2[i] = (byte) (((GetTabKey ^ b) ^ bArr[i]) + GetTabKey);
        }
        return bArr2;
    }

    public static byte[] decrypt(byte[] bArr) {
        byte[] bArr2 = new byte[12];
        byte b = bArr[0];
        bArr2[0] = b;
        for (int i = 1; i < 12; i++) {
            byte GetTabKey = GetTabKey(Byte.valueOf(bArr[i - 1]), i);
            bArr2[i] = (byte) (GetTabKey ^ ((bArr[i] - GetTabKey) ^ b));
        }
        return bArr2;
    }

    public static byte[] sendBytes(byte[] bArr, int i) {
        byte[] bArr2 = new byte[12];
        bArr2[0] = (byte) 35;
        int i2 = 0;
        while (i2 < i) {
            byte b = bArr[i2];
            i2++;
            bArr2[i2] = b;
        }
        bArr2[11] = (byte) calcCheckSum(bArr2, 11);
        for (int i3 = 0; i3 < 12; i3++) {
            byte b2 = bArr2[i3];
        }
        return Encrypt(bArr2);
    }

     public static void main(String []args){

         byte[] bArr = new byte[10];
        bArr[0] = 90;
        bArr[1] = 0;
        bArr[2] = 0;
        bArr[3] = 1;
        bArr[4] = 96;
        bArr[5] = 3;
        bArr[6] = (byte) 0; // thrust 0-100
        bArr[7] = (byte) 0; // vibe 0-100
        bArr[8] = 0;
        bArr[9] = 0;
        byte[] out = sendBytes(bArr, 10);

        System.out.println(bytesToHex(out));
     }
}