Requires mapping the signed key (serial+opts) to the Rigol license format. It looks like docmandu has done this. I'm working on it now; hopefully someone will paste working code before me. Why not help work on it? Shouldn't take too long.
alan2k: can you stop posting if you are just going to erase the posts?
alan2k: can you stop posting if you are just going to erase the posts?
+1, its so fucking annoying to read thru those junks in this really great thread
, ignore list updated.
Requires mapping the signed key (serial+opts) to the Rigol license format. It looks like docmandu has done this. I'm working on it now; hopefully someone will paste working code before me. Why not help work on it? Shouldn't take too long.
alan2k: can you stop posting if you are just going to erase the posts?
Right, well I can certainly can help test with my scope if that helps. Ill keep an eye on this.
If there is some code to write I am pretty good in python, c not at all really.
Language doesn't matter
The only references I have is the rigol-to-hex mapping function in main.c, the valid character list, and some valid mapped keys as listed in this thread
edit: mostly done, I think I still have a bug, but I can't generate to test...same issue that I thought I read before (did alank2 delete it? he ruins the discussion), where seed does vary what I see in signed.ecs.
edit 2: don't know what I did while playing with it, now I can generate the sample listed here.
edit 3: hexkey to rigol key done. but ecsign still doesn't work for any other key/serial other than the demo posted earlier, with the seed posted earlier...
cool stuff, i have a tool that can generate key strings, will release shortly.
i must admit i got the private key yesterday via mail from a guy already, but my ecs tools where so heavily "recoded", the just outputted crap ;-)
should have something this night (GMT) ;-)
Keeping a very close eye on this thread....very exciting! Great work guys!
alright, I found the bug... still not sure what it is, something with how the file is edited... echo -n 'DS2A123456789XXXX' > lic works...
So now I can generate license code strings.
$ echo -n "DS2A123456873VSA9" > lic; echo -e "123879325\nlic\n" | ./ecsign | php gen.php; ./riglol `php gen.php`
MVVD4QW-CSSG5HS-GMAAMER-J3VS9L4 DS2A123456873
serial: DS2A123456873
license-key: MVVD4QWCSSG5HSGMAAMERJ3VS9L4
license-skipped: MVD4QWCSG5HSGMAMERJ3VSL4 (5CC7A7505036CF032C0B23D199C15)
license-1-mapped: 5CC7A7505036CF
license-2-mapped: 32C0B23D199C15
license-options: VSA9 (9C01)
serial&options: DS2A123456873VSA9
sha1(serial&opts) D3B9717C00057C72EDFD409F62F2F10EE04135F2
v: 5CC7A7505036CF
lic1: 5CC7A7505036CF
License Key is VALID
Questions for others investigating:
1. Is VSA9 the only code that should / can be used? Other codes don't seem to generate valid keys.
2. I generated a key for my scope that passed riglol, but it didn't work (License is unavailable! error)
Should I try different seeds since the codes change?
enjoy ! - now i can finaly put by scope back together ;-)
UPDATE: for a DS2000 use
DSA9 as option key !
/*
** rigol ds2000 keygen / cybernet & the-eevblog-users
**
** to compile this you need MIRACL from [url]https://github.com/CertiVox/MIRACL[/url]
** download the master.zip into a new folder and run 'unzip -j -aa -L master.zip'
** then run 'bash linux' to build the miracle.a library
**
** BUILD WITH:
**
** gcc rikey.c -I../MIRACL ../MIRACL/miracl.a -o rikey
**
** adapt -I and path to miracl.a to your environment
**
** more info: https://www.eevblog.com/forum/testgear/sniffing-the-rigol's-internal-i2c-bus/
**
** then fetch private key from EEV Blog and put into "private_key[]=" below, do not prefix with 0x
** supply your serial and wanted options, and enjoy !
**
**
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "miracl.h"
#define RIGOL_DS2000
// START OF SETTINGS FOR ECC
#ifdef RIGOL_DS2000
unsigned char private_key[]="8....."; // <- RILOL FILL ME (no 0x prefix !)
unsigned char prime1[]="AEBF94CEE3E707";
unsigned char prime2[]="AEBF94D5C6AA71";
unsigned char curve_a[]="2982";
unsigned char curve_b[]="3408";
unsigned char point1[]="7A3E808599A525";
unsigned char point2[]="28BE7FAFD2A052";
#endif
// END OF SETTINGS FOR ECC
unsigned char codemap_ee00d0[]={ 0x0, 0x0, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2,
0x3, 0x4, 0x5, 0x6, 0x7, 0x0, 0x8, 0x9, 0xa, 0xb,
0xc, 0x0, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
0x15,0x16, 0x17 };
unsigned char codemap_20688e[]={ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, /* 0-9 = 0x30 */
0x37, 0x37, 0x37, 0x37, 0x37, 0x37 }; /* A-F = 0x37 */
unsigned char vb[]={'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9'};
void show_help(void)
{
printf("./rikey <DSA2XXXXXXXXX> <OPTS>\n\n");
printf("<DSA2XXXXXXXXX> - serial number of device\n");
printf("<OPTS> - \n");
printf("\t\tDSA? for permanent options\n");
printf("\t\tVSA? for temporary options\n");
printf("\n\n");
}
/*
** take serial and options make sha1 hash out of it
*/
static void hashing(unsigned char *opt_str,big hash)
{ /* compute hash function */
char *p;
char h[20];
int ch;
sha sh;
shs_init(&sh);
p=opt_str;
while(*p)
{
shs_process(&sh,*p);
p++;
}
shs_hash(&sh,h);
bytes_to_big(20,h,hash);
}
/*
** sign the secret message (serial + opts) with the private key
*/
int ecssign(unsigned char *serial, unsigned char *opt, unsigned char *lic1, unsigned char *lic2)
{
FILE *fp;
char ifname[50],ofname[50];
big a,b,p,q,x,y,d,r,s,k,hash;
epoint *g;
long seed;
int bits;
miracl *mip;
unsigned char *serial_options;
/* get public data */
mip=mirsys(0x320, 0x10); /* Use Hex internally */
mip->IOBASE=16;
a=mirvar(0);
b=mirvar(0);
p=mirvar(0);
q=mirvar(0);
x=mirvar(0);
y=mirvar(0);
d=mirvar(0);
r=mirvar(0);
s=mirvar(0);
k=mirvar(0);
hash=mirvar(0);
instr(p,prime1); /* modulus */
instr(a,curve_a); /* curve parameters */
instr(b,curve_b);
instr(q,prime2); /* order of (x,y) */
instr(x,point1); /* (x,y) point on curve of order q */
instr(y,point2);
/* randomise */
seed=1;
irand(seed);
ecurve_init(a,b,p,MR_PROJECTIVE); /* initialise curve */
g=epoint_init();
if (!epoint_set(x,y,0,g)) /* initialise point of order q */
{
printf("1. Problem - point (x,y) is not on the curve\n");
exit(0);
}
/* calculate r - this can be done offline,
and hence amortized to almost nothing */
bigrand(q,k);
ecurve_mult(k,g,g); /* see ebrick.c for method to speed this up */
epoint_get(g,r,r);
divide(r,q,q);
/* get private key of signer */
instr(d, private_key);
/* calculate message digest */
serial_options=calloc(128,1);
strcpy(serial_options, serial);
strcat(serial_options, opt);
hashing(serial_options,hash);
/* calculate s */
xgcd(k,q,k,k,k);
mad(d,r,hash,q,q,s);
mad(s,k,k,q,q,s);
cotstr(r,lic1);
cotstr(s,lic2);
return 0;
}
/*
** convert string to uppercase chars
*/
unsigned char *strtoupper(unsigned char *str)
{
unsigned char *newstr, *p;
p = newstr = (unsigned char*) strdup((char*)str);
while((*p++=toupper(*p)));
return newstr;
}
/*
**
*/
unsigned char code_map_206846(unsigned char i)
{
if ((i >= 'A') && (i <= 'F')) return(i-0x37);
if ((i >= '0') && (i <= '9')) return(i-0x30);
return(0x0);
}
/*
** Encryption Routine 1
*/
unsigned char *lic_code_map(unsigned char *lic_skipped)
{
unsigned char lv1,lv2;
unsigned char b1_mapped, b1_shifted, b1_remapped;
unsigned char b2_mapped, b2_shifted, b2_remapped;
unsigned char b3_mapped, b3_shifted, b3_remapped;
unsigned char b4_mapped, b4_shifted, b4_remapped;
unsigned char b5_shifted, b5_remapped;
unsigned char *lic_mapbytes;
lic_mapbytes=calloc(28, 1);
if (!lic_mapbytes) return(0);
lv1=lv2=0;
while(lv1 < strlen((unsigned char*)lic_skipped))
{
b1_mapped = codemap_ee00d0[ *(lic_skipped+lv1) - 0x30 ];
b1_shifted = (b1_mapped / 2) & 0xf;
b1_remapped = b1_shifted + codemap_20688e[b1_shifted];
lic_mapbytes[lv2++]=b1_remapped;
b1_mapped = b1_mapped & 0x1;
b2_mapped = codemap_ee00d0[ *(lic_skipped+lv1+1) - 0x30 ];
b2_shifted = ((b1_mapped << 0x3) | (b2_mapped / 4)) & 0xF;
b2_remapped = b2_shifted + codemap_20688e[b2_shifted];
lic_mapbytes[lv2++]=b2_remapped;
b3_mapped = codemap_ee00d0[ *(lic_skipped+lv1+2) - 0x30 ];
b3_shifted = ((b3_mapped / 8) | ( (b2_mapped & 0x3) << 2 )) & 0xF;
b3_remapped = b3_shifted + codemap_20688e[b3_shifted];
lic_mapbytes[lv2++]=b3_remapped;
b4_mapped = codemap_ee00d0[ *(lic_skipped+lv1+3) - 0x30 ];
b4_shifted = ((b4_mapped / 16 ) |((b3_mapped & 0x7) << 0x1)) & 0xf;
b4_remapped = b4_shifted + codemap_20688e[b4_shifted];
lic_mapbytes[lv2++]=b4_remapped;
b5_shifted = b4_mapped & 0xF;
b5_remapped = b5_shifted + codemap_20688e[b5_shifted];
lic_mapbytes[lv2++]=b5_remapped;
lv1 = lv1 + 4;
}
return(lic_mapbytes);
}
unsigned char * find_match5(unsigned char *code5)
{
unsigned char c1,c2,c3,c4;
unsigned char *input;
unsigned char *lic_mapbytes;
input=calloc(40,1);
/* lets bruteforce it ;-) */
for (c1=0;c1<sizeof(vb);c1++) {
for (c2=0;c2<sizeof(vb);c2++) {
for (c3=0;c3<sizeof(vb);c3++) {
for (c4=0;c4<sizeof(vb);c4++) {
input[0]=vb[c1];
input[1]=vb[c2];
input[2]=vb[c3];
input[3]=vb[c4];
input[4]='\0';
lic_mapbytes=lic_code_map(input);
if (!strcmp(lic_mapbytes, code5))
{
return(input);
}
}
}
}
}
return(0); // no match
}
int main(int argc, char *argv[0])
{
unsigned char *options,*lic1_code, *lic2_code, *lic_all;
unsigned char *out,*chunk,*temp,*final;
unsigned char *lic1_key, *lic2_key;
unsigned char *serial;
int v,i=0;
if (strlen(private_key)<14)
{
printf("\n\n");
printf("set the private_key variable on top of this file\n");
printf("you can find it here: https://www.eevblog.com/forum/testgear/sniffing-the-rigol's-internal-i2c-bus/msg264690/#msg264690\n");
printf("\n\n");
exit(-1);
}
if (argc != 3)
{
show_help();
exit(-1);
}
serial=strtoupper((unsigned char*)argv[1]);
options=strtoupper((unsigned char*)argv[2]);
if (strlen(serial)<13)
{
printf("\nINVALID SERIAL LENGTH\n");
show_help();
exit(-1);
}
if (strlen(options)!=4)
{
printf("\nINVALID OPTIONS LENGTH\n");
show_help();
exit(-1);
}
printf("serial: %s\n", serial);
printf("options: %s\n", options);
/* sign the message */
lic1_code=calloc(64,1);
lic2_code=calloc(64,1);
ecssign(serial,options,lic1_code, lic2_code);
printf("lic1-code: %s\n", lic1_code);
printf("lic2-code: %s\n", lic2_code);
lic_all=calloc(128,1);
temp=calloc(128,1);
chunk=calloc(6,1);
final=calloc(128,1);
lic1_key=calloc(20,1);
lic2_key=calloc(20,1);
strcpy(lic_all, lic1_code);
strcat(lic_all, "0");
strcat(lic_all, lic2_code);
printf("target-code: %s\n", lic_all);
// split in 5 byte groups and run bruteforce
// run or lic1_code
strcat(lic1_code,"0");
while(i<=strlen(lic1_code))
{
memcpy(chunk,lic1_code+i,5);
out=find_match5(chunk);
if (out)
{
strcat(temp, out);
}
i=i+5;
}
strcpy(lic1_key, temp);
// run for lic2_code
strcpy(temp,"");
i=0;
while(i<strlen(lic2_code))
{
memcpy(chunk,lic2_code+i,5);
if (strlen(chunk)<5)
{
for(v=0;v<5-strlen(chunk);v++)
strcat(chunk,"0");
}
out=find_match5(chunk);
if (out)
{
strcat(temp, out);
}
i=i+5;
}
strcpy(lic2_key, temp);
strcpy(temp, lic1_key);
strcat(temp, lic2_key);
// now add the options
memcpy(final, temp, 1);
final[1]=options[0];
memcpy(final+2, temp+1,7);
final[9]=options[1];
memcpy(final+10, temp+8,7);
final[17]=options[2];
memcpy(final+18, temp+15,7);
final[25]=options[3];
memcpy(final+26, temp+22,4);
printf("----------------------------------------------------\n");
printf("your-license-key: ");
for(i=0;i<strlen(final);i++)
{
if (i%7==0 && i>0) printf("-");
printf("%c", final[i]);
}
printf("\n");
printf("----------------------------------------------------\n");
}
there is some bug, working in it ... so hold your breath for now ;-)
bug fixed. SERIAL is 14 chars not 13 .. i corrected that - and one word of caution, my SERIAL number has just reverted to DS2A0...1 after playing with FW up/down grades
i give a f*ck - but be carefull ;-)
tested with FW05 and FW02 - works.
as long as you can spot the common.ecs parameters in the firmware (aka riglol.c) it should be fine.
some DS4 user should give it a try and report ;-)
Amazing, very well done! Has anyone tried to Sniffing the Rigol's internal SPI bus of the LMH6518 to see if it works at 350MHz, or 200MHz?
Cheers.
suggest you read the WHOLE thread, your answers are there.
Not at home atm‚ so excuse my terseness.
cybernet, you don't need to brute force to go back to serial format. look at my first post in this thread for the algo.
just need to take 5 bits at a time and convert them back to a character.
Not at home atm‚ so excuse my terseness.
cybernet, you don't need to brute force to go back to serial format. look at my first post in this thread for the algo.
just need to take 5 bits at a time and convert them back to a character.
true, but i thought its a tiny bit cooler, if it actually bruteforces SOMETHING in the process ;-)
im sure some windows guys will do a nice .exe for that .. they can do it more elegant then ..
Works for me on latest firmware on a 2102.
enjoy ! - now i can finaly put by scope back together ;-)
Big thanks to all involved!
I can confirm it worked on my recently purchased DS2072 (shipped with latest 01.01.00.02 fw), using DSAZ. I also had ~1900 minutes on the trials remaining at the time of entering the key. It's now a DS2202 with all options "offcial version"
Edit: Also restarted the scope several times just to make sure the options stuck!
Bah, can't get MIRACL to build with cygwin.
Someone make a windows executable. With installer. And an android app
Cue, lots of serial numbers being PM'd to a few people on here ! :-)
--
Darryl
dave should host a keygen ;-) a bit of php and it runs ...
FYI: My serial on my new 3 day old DS2102 is 13 chars, not 14
DS2A151900xxx
FYI: My serial on my new 3 day old DS2102 is 13 chars, not 14
DS2A151900xxx
strange, but as long as the secret message matches, it should work as well - will update above code to also allow 13 then.
Just some quick feedback.
I have a DS2072 with a DS2A1517xxxxx serial. I can generate the license key, but the scope does not accept it. I have used "DSAZ" as the option key.
cybernet, my serial is 13 chars also, DS2A1527XXXXX