Author Topic: Sniffing the Rigol's internal I2C bus  (Read 1840406 times)

0 Members and 4 Guests are viewing this topic.

Offline Git

  • Contributor
  • Posts: 13
  • Country: gb
  • Very old engineer with over 4 decades in design.
Re: Sniffing the Rigol's internal I2C bus
« Reply #2350 on: January 06, 2014, 10:23:05 pm »
Does anybody have IDA sigs for the compiler and maybe crypto libraries used for the DS firmware please?

Git
 

Offline zombie28

  • Regular Contributor
  • *
  • Posts: 69
Re: Sniffing the Rigol's internal I2C bus
« Reply #2351 on: January 06, 2014, 11:22:37 pm »
I've got some good and bad news. The good news is that I finished implementation of signature verification algorithm and tested its correctness on some 'A'-type license codes. However the bad news is that encryption keys needed by this algorithm are not consistent among different memory dumps of different scopes. It looks like Rigol uses different key sets in 'A' product line, but I don't have enough memory dumps to tell whether it is per scope model, production week or maybe even per single unit. Even ECC public keys are different, so it requires breaking them every time the new key is issued. Fortunately Rigol didn't change elliptic curve parameters, so finding private key is a matter of milliseconds on a decent computer.
 

Offline zombie28

  • Regular Contributor
  • *
  • Posts: 69
Re: Sniffing the Rigol's internal I2C bus
« Reply #2352 on: January 06, 2014, 11:25:23 pm »
How this binary 32 bit return value gets hashed by the ECC-signature verification?

I will publish complete algorithm soon.
 

Offline zombie28

  • Regular Contributor
  • *
  • Posts: 69
Re: Sniffing the Rigol's internal I2C bus
« Reply #2353 on: January 06, 2014, 11:50:49 pm »
So here it is:

Code: [Select]
//
// Copyright (c) 2014 RIGLOL Technologies, Inc. All Rights Reversed.
// This product includes software developed by the OpenSSL Project
// for use in the OpenSSL Toolkit. (http://www.openssl.org/)
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include "rc5.h"

extern "C"
{
#include "miracl.h"
}

// ECC parameters
char A[] = "2982";
char B[] = "3408";
char P[] = "AEBF94CEE3E707";
char N[] = "AEBF94D5C6AA71";
char Gx[] = "7A3E808599A525";
char Gy[] = "28BE7FAFD2A052";

typedef unsigned char uint8;
typedef unsigned int uint32;
typedef unsigned long long uint64;

#define LICENSE_CODE_LENGTH 28

// sample key sets for different scopes
#if 1
// DS2D1542....
static const uint8 RC5Key1[16] = { 0x3F, 0x57, 0x8E, 0x1C, 0x44, 0x18, 0x34, 0xDD, 0xA5, 0x46, 0x21, 0x36, 0x32, 0x81, 0xFB, 0xCF };
static const uint8 RC5Key2[16] = { 0x14, 0xDC, 0x15, 0xAF, 0xA1, 0x48, 0x3D, 0x7D, 0x6A, 0xC1, 0xDC, 0xA1, 0x79, 0x8D, 0xAA, 0x3E };
static const uint8 XXTEAKey[16] = { 0x39, 0x69, 0xA2, 0x04, 0x55, 0x9C, 0x35, 0x52, 0x90, 0x44, 0xED, 0x85, 0x52, 0x16, 0x13, 0x32 };
char ECCPublicKey[] = "A51BF373712F7D";
#else
// DS2D1543....
static const uint8 RC5Key1[16] = { 0x41, 0x55, 0xBF, 0xD8, 0x2D, 0x42, 0x9E, 0xA6, 0x9B, 0x3E, 0xE7, 0xD7, 0xD5, 0x9C, 0x89, 0x06 };
static const uint8 RC5Key2[16] = { 0xB9, 0xBC, 0x53, 0xD8, 0xB8, 0xCE, 0x6C, 0xE3, 0x59, 0x45, 0x55, 0xAA, 0x89, 0x55, 0x65, 0x43 };
static const uint8 XXTEAKey[16] = { 0x86, 0xF4, 0xA0, 0x93, 0x0B, 0xC7, 0xED, 0x27, 0x6B, 0x2D, 0x6C, 0x2C, 0xE2, 0x93, 0x53, 0x5F };
char ECCPublicKey[] = "A0581020E5C012";
#endif

uint32 DecodeChar(char value)
{
char *charMap = "LRE8YFGHJK9SNBQ36MPVWXAZ2U45TC7D";
char *charPos = strchr(charMap, value);
return charPos == NULL ? 0 : charPos - charMap;
}

uint64 DecodeSignature(uint64 value)
{
uint32 shiftCount = value & 0x0f;
do value >>= 4; while(shiftCount-- > 0);
return value;
}

uint32 DecodeLicenseCode(char *licenseCode, uint64& sig1, uint64& sig2)
{
if(strlen(licenseCode) != LICENSE_CODE_LENGTH)
return 0;

uint8 licenseBits[35];

for(int i = 0, j = 0; i < LICENSE_CODE_LENGTH; i += 4, j += 5)
{
uint32 bitBuffer =
(DecodeChar(licenseCode[i]) << 15) +
(DecodeChar(licenseCode[i+1]) << 10) +
(DecodeChar(licenseCode[i+2]) << 5) +
DecodeChar(licenseCode[i+3]);

licenseBits[j] = bitBuffer >> 16;
licenseBits[j+1] = (bitBuffer >> 12) & 0xf;
licenseBits[j+2] = (bitBuffer >> 8) & 0xf;
licenseBits[j+3] = (bitBuffer >> 4) & 0xf;
licenseBits[j+4] = bitBuffer & 0xf;
}

uint64 RC5Block1 = 0;
uint64 RC5Block2 = 0;

for(int i = 0; i < 16; i++)
{
RC5Block1 |= uint64(licenseBits[i]) << i*4;
RC5Block2 |= uint64(licenseBits[i + 16]) << i*4;
}

RC5_32_KEY RC5Key;

RC5_32_set_key(&RC5Key, 16, RC5Key1, 16);
RC5_32_ecb_encrypt((uint8*)&RC5Block1, (uint8*)&RC5Block1, &RC5Key, 1);

RC5_32_set_key(&RC5Key, 16, RC5Key2, 16);
RC5_32_ecb_encrypt((uint8*)&RC5Block2, (uint8*)&RC5Block2, &RC5Key, 0);

// ECDSA signature
sig1 = DecodeSignature((RC5Block2 >> 8) | (uint64(licenseBits[33]) << 56));
sig2 = DecodeSignature(((RC5Block1 & 0xffffffffffff) << 8) | (RC5Block2 & 0xff) | (uint64(licenseBits[32]) << 56));

// option bits
return uint32(RC5Block1 >> 48) | (uint32(licenseBits[34]) << 16);
}

char* EncodeOptionBits(uint32 optionBits)
{
char *charMap = "XBCNEF8HJ3LMKPZRSAUVWTYQ5D4276G9";
char *optionString = new char[5];

for(int i = 0; i < 4; i++)
optionString[i] = charMap[(optionBits >> ((3-i)*5)) & 0x1f];

optionString[4] = '\0';
return optionString;
}

char* EncodeSerialNumber(char *serialNumber)
{
if(strlen(serialNumber) < 4)
return 0;

uint32 header = *((uint32*)serialNumber);

for(int i = 0; i < 16; i++)
header =
(header << 1) |
(header >> 31) ^
(header >> 30) & 1 ^
(header >> 28) & 1 ^
(header >> 22) & 1 ^
(header >> 13) & 1 ^
(header >> 6) & 1;

char* result = strdup(serialNumber);
*((uint32*)result) = header;
return result;
}

#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
 
void XXTEA(uint32 *v, int n, uint32 const key[4])
{
uint32 y, z, sum;
unsigned p, rounds, e;

if (n > 1)
{
rounds = 6 + 52/n;
sum = 0;
z = v[n-1];
do {
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++)
{
y = v[p+1];
z = v[p] += MX;
}
y = v[0];
z = v[n-1] += MX;
} while (--rounds);
}
else if (n < -1)
{
n = -n;
rounds = 6 + 52/n;
sum = rounds*DELTA;
y = v[0];
do {
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--)
{
z = v[p-1];
y = v[p] -= MX;
}
z = v[n-1];
y = v[0] -= MX;
} while ((sum -= DELTA) != 0);
}
}

uint64 ByteSwap64(uint64 value)
{
uint64 result = 0;
for(int i = 0; i < 8; i++)
{
result = (result << 8) | (value & 0xff);
value >>= 8;
}
return result;
}

bool VerifySignature(uint64 sig1, uint64 sig2, uint8 signatureDataHash[20])
{
mirsys(0x320, 16)->IOBASE = 16;

big p = mirvar(0);
big n = mirvar(0);
big a = mirvar(0);
big b = mirvar(0);
big x = mirvar(0);
big y = mirvar(0);
big lic1 = mirvar(0);
big lic2 = mirvar(0);
big hash = mirvar(0);
big m1 = mirvar(0);
big m2 = mirvar(0);
big v = mirvar(0);
big g = mirvar(0);

epoint *pt1 = epoint_init();
epoint *pt2 = epoint_init();

instr(a, A);
instr(b, B);
instr(p, P);
instr(n, N);
 
ecurve_init(a, b, p, MR_PROJECTIVE);

instr(x, Gx);
instr(y, Gy);
if (!epoint_set(x, y, 0, pt1))
{
printf("ERR: Point G is invalid\n");
exit(-1);
}

instr(x, ECCPublicKey);
if (!epoint_set(x, x, 1, pt2))
{
printf("ERR: Public key is invalid\n");
exit(-1);
}
 
bytes_to_big(20, (char*)signatureDataHash, hash);

sig1 = ByteSwap64(sig1);
bytes_to_big(8, (char*)&sig1, lic1);

sig2 = ByteSwap64(sig2);
bytes_to_big(8, (char*)&sig2, lic2);

xgcd(lic2, n, lic2, lic2, lic2);
copy(lic2, g);
mad(hash, g, g, n, n, m1);
mad(lic1, g, g, n, n, m2);
ecurve_mult2(m1, pt1, m2, pt2, pt1);
epoint_get(pt1, v, v);
divide(v, n, n);

return mr_compare(v, lic1) == 0;
}

bool VerifyLicenseCode(char *serialNumber, char *licenseCode)
{
uint64 sig1, sig2;
uint32 optionBits = DecodeLicenseCode(licenseCode, sig1, sig2);

char *optionString = EncodeOptionBits(optionBits);
char *encodedSerialNumber = EncodeSerialNumber(serialNumber);

uint32 optionStringLength = strlen(optionString);
uint32 encodedSerialNumberLength = strlen(encodedSerialNumber);

uint32 signatureDataLength = (encodedSerialNumberLength + optionStringLength + 3) & ~3;
uint8 *signatureData = new uint8[signatureDataLength];

memset(signatureData, 0, signatureDataLength);
memcpy(signatureData, encodedSerialNumber, encodedSerialNumberLength);
memcpy(signatureData + encodedSerialNumberLength, optionString, optionStringLength);

XXTEA((uint32*)signatureData, signatureDataLength >> 2, (uint32*)XXTEAKey);

uint8 hash[20];
sha sh;
shs_init(&sh);
for(int i = 0; i < signatureDataLength; i++)
shs_process(&sh, signatureData[i]);
shs_hash(&sh, (char*)hash);

return VerifySignature(sig1, sig2, hash);
}
 

Offline tirulerbach

  • Contributor
  • Posts: 33
Re: Sniffing the Rigol's internal I2C bus
« Reply #2354 on: January 07, 2014, 12:40:38 am »
So here it is:

Thank you again, zombie28. Very valuable work.  :-+

So now I have to rework my keygen. I was just to about to release a first shot. It will take some more time. Is anybody else writing a keygen, too?

However the bad news is that encryption keys needed by this algorithm are not consistent among different memory dumps of different scopes. It looks like Rigol uses different key sets in 'A' product line, but I don't have enough memory dumps to tell whether it is per scope model, production week or maybe even per single unit. Even ECC public keys are different, so it requires breaking them every time the new key is issued.

Where are the public keys stored? Flash? Then maybe it's a model dependency.
« Last Edit: January 07, 2014, 12:46:06 am by tirulerbach »
 

Offline AndreaEl

  • Contributor
  • Posts: 40
  • Country: it
Re: Sniffing the Rigol's internal I2C bus
« Reply #2355 on: January 07, 2014, 01:17:17 pm »
Are some days that i not follow this topic and i have some question that i have not understand...

I have a Rigol DS2072 (HW 2)
I have a not update firmware and i must update, is right that the last version is: 00.02.01.00.03? (I have read about clear FRAM after update).

With this version is available the 300MHz BW Option, but i have read that 200MHz BW option give more performance in LF than 300MHz in HW 1. Is the same for HW 2 or i can Install 300MHz BW with no problem in my HW 2?

I have read about newest code for enable 300MHz and CAN, but not understand what enable each code. I have read about DSHH, DSGH etc.
I search for: 200MHz + All Option (include CAN), 300MHz + All Option.
My equipment:

Multimeter: HP 34401A, HP 3478A, HP 3466A, Fluke 115
Oscilloscope: Rigol DS2072 (DS2202)
Function generator: SRS DS335
Electronic load: Maynuo M9811
Power supply: TDK-Lambda ZUP 20-20, 2x Atten TPR3602A, Atten APR1505A, Atten APR12001A, Atten AT1001D
 

Offline neslekkim

  • Super Contributor
  • ***
  • Posts: 1305
  • Country: no
Re: Sniffing the Rigol's internal I2C bus
« Reply #2356 on: January 07, 2014, 05:02:34 pm »
Hm... An DS2202A-S have serial that starts with DS2E...

« Last Edit: January 07, 2014, 10:33:17 pm by neslekkim »
 

Offline battlefield

  • Newbie
  • Posts: 8
Re: Sniffing the Rigol's internal I2C bus
« Reply #2357 on: January 07, 2014, 05:46:19 pm »
I just joined the forums and had a brief read over the last few pages of the topic.
I also just got my rigol DS2072A with serial DS2D1546... I'd love to help you with key breaking but do far as I understand you need memory dumps and for that I have two questions about that, first one is do I need JTAG or something else, second how exactly do I acces these memory dumps.
 

Offline NikWing

  • Regular Contributor
  • *
  • Posts: 139
  • Country: de
Re: Sniffing the Rigol's internal I2C bus
« Reply #2358 on: January 07, 2014, 06:23:09 pm »
you need jtag with a special pin setup/adapter and you have to open the DSO

but cybernet posted something a few days ago, it seemed to me it might be possible to dump via a LAN connection ...
but I dunno XD
 

Offline Carrington

  • Super Contributor
  • ***
  • Posts: 1202
  • Country: es
Re: Sniffing the Rigol's internal I2C bus
« Reply #2359 on: January 07, 2014, 07:02:10 pm »
cybernet choose another path from the beginning, but why? ;D
My English can be pretty bad, so suggestions are welcome. ;)
Space Weather.
Lightning & Thunderstorms in Real Time.
 

Offline neslekkim

  • Super Contributor
  • ***
  • Posts: 1305
  • Country: no
Re: Sniffing the Rigol's internal I2C bus
« Reply #2360 on: January 07, 2014, 10:34:04 pm »
No others with the -S version yet?, to see if the E in the serial is due to the signalgen or not?
 

Offline tirulerbach

  • Contributor
  • Posts: 33
Re: Sniffing the Rigol's internal I2C bus
« Reply #2361 on: January 08, 2014, 12:55:26 pm »
I'm making progress with the keygen für the DS2k-A.  :box:

But I need assistance:  :-//
  • I need some pointer, links, code etc., how to break für the ecc private key given the public key.
  • I need some info how to extract the public key from a memory dump.
Any help is appreciated. Thank you in advance!   ;D

« Last Edit: January 08, 2014, 01:15:14 pm by tirulerbach »
 

Offline tirulerbach

  • Contributor
  • Posts: 33
Re: Sniffing the Rigol's internal I2C bus
« Reply #2362 on: January 08, 2014, 02:29:57 pm »
8)  O0  :-DD

My DS2202A:




Crowd: Please be patient! There are still some issues with the keygen. It is not ready for the masses. :-[

In the meantime, please provide memory dumps. Search and read this thread: all information how to do this is in here. No pain, no gain!  >:D

« Last Edit: January 08, 2014, 02:42:03 pm by tirulerbach »
 

Offline neslekkim

  • Super Contributor
  • ***
  • Posts: 1305
  • Country: no
Re: Sniffing the Rigol's internal I2C bus
« Reply #2363 on: January 08, 2014, 02:58:17 pm »
My DS2202A:

Interresting!, did you see the thing about that my DS2202A-S have DS2E, not DS2D?
 

Offline zombie28

  • Regular Contributor
  • *
  • Posts: 69
Re: Sniffing the Rigol's internal I2C bus
« Reply #2364 on: January 08, 2014, 03:29:24 pm »
But I need assistance:  :-//
  • I need some pointer, links, code etc., how to break für the ecc private key given the public key.
  • I need some info how to extract the public key from a memory dump.

PM sent
 

Offline NikWing

  • Regular Contributor
  • *
  • Posts: 139
  • Country: de
Re: Sniffing the Rigol's internal I2C bus
« Reply #2365 on: January 08, 2014, 03:35:37 pm »
yes, the generator versions seem to have a count up in the serial ...

I'm looking forward to test the stuff you people come up with :D
can't await :D
(though I still have 4000 min left lol)
 

Offline sled

  • Contributor
  • Posts: 21
  • Country: ch
Re: Sniffing the Rigol's internal I2C bus
« Reply #2366 on: January 08, 2014, 03:41:13 pm »
8)  O0  :-DD

Crowd: Please be patient! There are still some issues with the keygen. It is not ready for the masses. :-[

In the meantime, please provide memory dumps. Search and read this thread: all information how to do this is in here. No pain, no gain!  >:D

congrats! really good work :) it seems like the bandwidth (100/200/300 mhz) is not an option anymore does that mean the bandwidth is dependent on the model number/serial number?
 

Offline alank2

  • Super Contributor
  • ***
  • Posts: 2185
Re: Sniffing the Rigol's internal I2C bus
« Reply #2367 on: January 08, 2014, 03:43:00 pm »
it seems like the bandwidth (100/200/300 mhz) is not an option anymore

I don't think you can make this assumption, bandwidth upgrades are only displayed in the menu if they are activated.
 

Offline zombie28

  • Regular Contributor
  • *
  • Posts: 69
Re: Sniffing the Rigol's internal I2C bus
« Reply #2368 on: January 08, 2014, 03:49:34 pm »
My DS2202A:

Interresting!, did you see the thing about that my DS2202A-S have DS2E, not DS2D?

This should not pose any problem - any letter after 'DS2' except 'A' and 'C' should work with the new keygen. It would be interesting to compare keys from your scope to tirulerbach's ones.
 

Offline blandin_01

  • Newbie
  • Posts: 3
  • Country: ru
Re: Sniffing the Rigol's internal I2C bus
« Reply #2369 on: January 08, 2014, 04:33:22 pm »
have a few questions:
1. should enable signals "TRST" and "SRST" in scheme of Cybernet?
2. You can use H-JTAG V2.1 instead http://www.urjtag.org/  ?
3. well use jtag-LPT(Parallel-port cables)?
4. dump from (DS2072A) DS2D1546..... need?
 

Offline zombie28

  • Regular Contributor
  • *
  • Posts: 69
Re: Sniffing the Rigol's internal I2C bus
« Reply #2370 on: January 08, 2014, 04:55:59 pm »
In order to extract keys from memory dumps you need to search for the following sequence of bytes (in hex):

Code: [Select]
02 00 84 00 10 00 <16 bytes of XXTEAKey> 20 00 <2x16 bytes of RC5Key1 and RC5Key2> 08 00 <8 bytes of bit-shuffled ECC public key> 40 00 <64 bytes of some ASCII-HEX data>

You will need to unshuffle the public key with the algorithm I posted earlier in this thread.
 

Offline Posterisan

  • Newbie
  • Posts: 7
  • Country: de
Re: Sniffing the Rigol's internal I2C bus
« Reply #2371 on: January 08, 2014, 07:06:31 pm »
Why are the public keys differ in the A models? As far as I have read it's the same firmware as the non-A models. Or are the public keys stored somewhere else?
 

Offline tirulerbach

  • Contributor
  • Posts: 33
Re: Sniffing the Rigol's internal I2C bus
« Reply #2372 on: January 08, 2014, 07:15:51 pm »
So, now I'm diving into Elliptic Curve Cryptography...  Pretty interesting stuff... :-DD

So I have a question: How do I calculate the Y coordinate of the public key X coordinate out of the ECC curve parameters, base point and order?

Second, the keygen is getting complex and a lot of work. Are there any people out here who can program C and would like to help?  ???

I need:

Code: [Select]
struct KeyData
{
  char RC5Key1[32 + 1]; // hex string
  char RC5Key2[32 + 1]; // hex string
  char XXTEAKey[32 + 1]; // hex string
  char serialNumber[TBD];
  char publicKey[TBD]; // hex string
  char secretKey[TBD];        // hex string
};

struct KeyData * LoadKeyData(char *filename);
int SaveKeyData(char *filename);

char * FormatHex(uint8_t *bytes, unsigned int len);
unsigned int ParseHex(uint8_t *buffer, unsigned int capacity, char *hexstring);

uint8_t * ScanMemoryDump(char *filename);


The Load() and Save() functions should use ASCII-Files. Lines should like something like "serial=DS....." or "RC5Key1: 123456789abcdef...." and so on. Please don't use Windows specific functions, only pure ANSI. The keygen works on linux and windows.

The function FormatHex() should malloc() the string. ParseHex() returns the number of bytes parsed, or zero, if buffer was to small.

ScanMemoryDump() opens a binary file and scans for the pattern zombie28 published.

Any assistance will be useful.  :-+
 

Offline tirulerbach

  • Contributor
  • Posts: 33
Re: Sniffing the Rigol's internal I2C bus
« Reply #2373 on: January 08, 2014, 07:25:17 pm »
Why are the public keys differ in the A models? As far as I have read it's the same firmware as the non-A models. Or are the public keys stored somewhere else?

This is simply currently not known. Maybe they are in someway calculated. But analyzing the firmware is pretty complex, difficult and time consuming. Thanks to zombie28 again for his effort. If we had more memory dumps, a better analysis maybe is possible. But it's the old problem: People are only sitting around and waiting for the keygen and don't would like to break her warranty seal on the scope to provide a memory dump... This is bad indeed...  ::)
 

Offline neamyalo

  • Contributor
  • Posts: 12
Re: Sniffing the Rigol's internal I2C bus
« Reply #2374 on: January 08, 2014, 07:40:24 pm »
tirulerbach,

I can create definitions for those functions tomorrow. I'll be using C++, so let me know if that's a problem for you.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf