Home
Rules
Help
Search
Quick Search
Advanced Search
[Close]
Login
Register
Welcome Guest, please
login
or
register
.
Username:
1 Hour
1 Day
1 Week
1 Month
Forever
Password:
News
: Welcome to Nintendo-Scene, enjoy your stay and don't forget to read the
Rules
before posting.
Nintendo-Scene Forums
Wii Forums
Wii Technical Hacking Discussion
(Moderator:
xboxbman
)
The crypto used for wii savegame files is sect233r1
Pages: [
1
]
0 Members and 1 Guest are viewing this topic.
Topic Tools
Topic Tools
Print
September 15, 2007, 10:33:55 AM
therealr
Newbii
Karma: +4/-0
Offline
Join date:
September 15 2007
Posts: 9
The crypto used for wii savegame files is sect233r1
--signed message begins--
Hello people,
I have discovered something fun while playing around with the savegame files: wii save files use elliptic curve cryptography with the NIST B 233 bit elliptic curve (identified as as sect233r1 in openssl).
Brief facts about the sect233r1 crypto system (google is your friend for more details): The private key is a 233 bit integer (29 byte + 1 bit). It is combined with a public keypair composed by two 233 bit integers. A ECDSA signature is composed by a pair of 232 bit integers (29 byte). A good way of doing encryption in this scheme is via Diffie-Hellman key exchange. A sender encrypts a message for a receiver by using the senders private and public keys. The receiver decrypts the same message by using the senders public key and the receivers private and public keys. Hence, for encryption/decryption *five* 233 bit integers are involved on either side.
It appears a Wii savegame file ends with a certificate chain. The certificates contains a public keypair (the one that is being "certified") and a signature (another number pair) from the signing entity. The number pairs are stored as a compound 60 bit data (first 30 bytes for the first number, and the next 30 bytes for the second). Hence, the first and middle byte is always 00 or 01 for keys, and 00 for signatures. One can check that the keys are indeed NIST B 233 keys using openssls EC_KEY_check_key function (code forthcoming).
With this background, lets speculate a bit regarding the certificates. By looking at savegame files it seems the certificate format may roughly be:
[Magic number 0x00010002]
[Certificate signature from signing entity]
[Name of signing entity]
[Name of entity being certified]
[Public key pair of entity being certified]
The file ends with two such certificates, and the first one is always the same for save game files from the same console (barring a console wipe, which I haven't tried but I suspect generates a new key). Hence, this seems to be a certificate of your consoles public keys.
My guess for the second certificate is that it is for a temporary keypair generated for the specific Diffie-Hellman key exchange for the encryption of the file. So, I think the encryption involves a freshly generated private/public keypair; but the private key is not present in the save file and is likely discarded directly after encryption. Since the decryption of the data requires the public sender keys, they are included via the certificate, which is signed by the consoles permanent private key. But then what key is the receiver of the encryption? Since savegame files can be freely exchanged between consoles that do not know anything about each other, I *think* there must be some other shared private key that all consoles know about.
In the savegame file the certificates is preceded by another signature number pair. This is a non-certificate related signature, so I assume this is an ECDSA signature of the data in the file. However, I have not been able to verify this in any way; I haven't figured out what data is being signed; what digest type is being used; and which public keys verify it (not sure they are even in the file, it might be the public keys that go along with the over-all-consoles shared private key).
I have noticed that the documentation of the elliptic curve routines in openssl is severely lacking. Hence, in forthcoming posts I publish some example routines that works with elliptic curve cryptography. The first one, 'checkkey' can be used to verify that the public keys present in the certificates are indeed sect233r1 keys. You can try to change sect233r1 -> sect233k1 (a closely related curve) to see that the keys do not match that curve.
See you,
R (with hugs and kisses to M)
--signed message ends--
Message SHA1 hash: AF9DE52441929DC1E44A1C2BDAD41A5A8AF3F395
R's public sect233r1 key:
X: 019B1ABA43E2441860768FC7B71BE97EF86397ADE0E971DA4FB15F3C425A
Y: 003EAD804DCA533DF1EA4E8F3E74133EE2FEBC2C794AD3214FBB5089B760
Signature:
R: 00B72A7EB206533664E045A76C3B060A4E31933DC67310684B50D27BDB7D
S: 000F0034DD5B6AEEF53FD9FE6BFB2A6207FB1540058B99AF3BE66A2FEDA8
Logged
September 15, 2007, 10:37:11 AM
therealr
Newbii
Karma: +4/-0
Offline
Join date:
September 15 2007
Posts: 9
Re: The crypto used for wii savegame files is sect233r1
Code:
/* Educational program for checking the integrity of Elliptic Curve keys using openssl's libssl
* (c) 2007 R, Licensed under GNU GPL v3, see <http://www.gnu.org/licenses/> for details.
*
* compile with: gcc -o checkkey checkkey.c -lssl -Wall
*/
#include <stdlib.h>
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/ec.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ecdh.h>
#include <openssl/evp.h>
void fatalerror(char *message) {
fprintf(stderr,"\nError: %s\n",message);
fprintf(stderr,"%s\n",ERR_error_string(ERR_get_error(),NULL));
exit(1);
}
void writekey(BIO *bio,char *text,BIGNUM *bn) {
int size;
BIO_printf(bio,text);
size = strlen(BN_bn2hex(bn));
for(;size<60;size++) {
BIO_printf(bio,"0");
}
BIO_printf(bio,"%s\n",BN_bn2hex(bn));
}
int main(int argc,char *argv[]) {
EC_KEY *key = NULL;
BIO *bio_stderr;
EC_POINT *pub_key;
const EC_GROUP *group;
BIGNUM *pub_key_x = BN_new();
BIGNUM *pub_key_y = BN_new();
BIGNUM *priv_key = BN_new();
int ret;
SSL_library_init();
SSL_load_error_strings();
if(argc < 3 || argc > 4) {
fprintf(stderr,"\nUsage: checkkey [<private key>] <public key x> <public key y>\n\n");
fprintf(stderr,"Check if keys are valid. Can either check just public keypair,\n");
fprintf(stderr,"or that a triplet of a private key and a public keypair are valid and matches.\n");
fprintf(stderr,"Keys are given as compound hexadecimal strings.\n\n");
exit(1);
}
bio_stderr = BIO_new_fp(stderr, BIO_NOCLOSE);
key = EC_KEY_new_by_curve_name(NID_sect233r1);
if (key == NULL) {
fatalerror("EC_KEY_new_by_curve_name");
}
if(argc == 4) {
ret = BN_hex2bn(&priv_key,argv[1]);
ret = BN_hex2bn(&pub_key_x,argv[2]) && ret;
ret = BN_hex2bn(&pub_key_y,argv[3]) && ret;
} else {
ret = BN_hex2bn(&pub_key_x,argv[1]) && ret;
ret = BN_hex2bn(&pub_key_y,argv[2]) && ret;
}
if(ret == 0) {
fatalerror("Couldn't parse sender keys.");
}
if(argc == 4) {
if(!EC_KEY_set_private_key(key, priv_key)) {
fatalerror("EC_KEY_set_private_key");
}
}
group = EC_KEY_get0_group(key);
pub_key = EC_POINT_new(group);
if(!EC_POINT_set_affine_coordinates_GFp(group, pub_key, pub_key_x, pub_key_y, NULL)) {
fatalerror("EC_PINT_set_affine_coordinates_GFp");
}
if(!EC_KEY_set_public_key(key, pub_key)) {
fatalerror("EC_KEY_set_public_key");
}
BIO_printf(bio_stderr,"Read key data:\n");
if(argc == 4) {
writekey(bio_stderr,"PRIV: ",priv_key);
}
writekey(bio_stderr,"PUBX: ",pub_key_x);
writekey(bio_stderr,"PUBY: ",pub_key_y);
BIO_printf(bio_stderr,"Checking key: ");
if (!EC_KEY_check_key(key)) {
BIO_printf(bio_stderr," **** Key is invalid, libssl explaination follows: ****");
fatalerror("EC_KEY_check_key");
} else {
if(argc == 4) {
printf("**** Valid private and public keypair ****\n");
} else {
printf("**** Valid public key ****\n");
}
}
return 0;
}
Logged
September 15, 2007, 10:38:55 AM
therealr
Newbii
Karma: +4/-0
Offline
Join date:
September 15 2007
Posts: 9
Re: The crypto used for wii savegame files is sect233r1
Code:
/* Educational program for signing a text with Elliptic Curve crypto using openssl's libssl
* (c) 2007 R, Licensed under GNU GPL v3, see <http://www.gnu.org/licenses/> for details.
*
* compile with: gcc -o sign sign.c -lssl -lcrypto -Wall
*/
#include <stdlib.h>
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/ec.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ecdh.h>
#include <openssl/evp.h>
void fatalerror(char *message) {
fprintf(stderr,"\nError: %s\n",message);
fprintf(stderr,"%s\n",ERR_error_string(ERR_get_error(),NULL));
exit(1);
}
void writekey(BIO *bio,char *text,const BIGNUM *bn) {
int size;
BIO_printf(bio,text);
size = strlen(BN_bn2hex(bn));
for(;size<60;size++) {
BIO_printf(bio,"0");
}
BIO_printf(bio,"%s\n",BN_bn2hex(bn));
}
int main(int argc, char *argv[]) {
EC_KEY *key = NULL;
BIO *bio_stderr, *bio_stdin, *bio_stdout;
EC_POINT *pub_key;
const EC_GROUP *group;
BIGNUM *pub_key_x = BN_new();
BIGNUM *pub_key_y = BN_new();
BIGNUM *priv_key = BN_new();
BIGNUM *digest_bn = BN_new();
EVP_MD_CTX md_ctx;
ECDSA_SIG *signature = NULL;
int ret;
unsigned char inbuf[80];
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int dgst_len = 0, inlen = 0;
SSL_library_init();
SSL_load_error_strings();
if(argc < 4) {
fprintf(stderr,"\nUsage: sign <own private key> <own public key x>\n");
fprintf(stderr," <own public key y>\n\n");
fprintf(stderr,"Creates a signature for data on stdin.\n");
fprintf(stderr,"Keys are given as compound hexadecimal strings.\n");
exit(1);
}
bio_stdout = BIO_new_fp(stdout, BIO_NOCLOSE);
bio_stdin = BIO_new_fp(stdin, BIO_NOCLOSE);
bio_stderr = BIO_new_fp(stderr, BIO_NOCLOSE);
key = EC_KEY_new_by_curve_name(NID_sect233r1);
if (key == NULL) {
fatalerror("EC_KEY_new_by_curve_name");
}
ret = BN_hex2bn(&priv_key,argv[1]);
ret = BN_hex2bn(&pub_key_x,argv[2]) && ret;
ret = BN_hex2bn(&pub_key_y,argv[3]) && ret;
if(ret == 0) {
fatalerror("Couldn't parse sender keys.");
}
if(!EC_KEY_set_private_key(key, priv_key)) {
fatalerror("EC_KEY_set_private_key");
}
group = EC_KEY_get0_group(key);
pub_key = EC_POINT_new(group);
if(!EC_POINT_set_affine_coordinates_GFp(group, pub_key, pub_key_x, pub_key_y, NULL)) {
fatalerror("EC_PINT_set_affine_coordinates_GFp");
}
if(!EC_KEY_set_public_key(key, pub_key)) {
fatalerror("EC_KEY_set_public_key");
}
BIO_printf(bio_stderr,"Read key data:\n");
writekey(bio_stderr,"PRIV: ",priv_key);
writekey(bio_stderr,"PUBX: ",pub_key_x);
writekey(bio_stderr,"PUBY: ",pub_key_y);
if (!EC_KEY_check_key(key)) {
fatalerror("EC_KEY_check_key");
}
BIO_printf(bio_stderr,"Creating digest.\n");
EVP_MD_CTX_init(&md_ctx);
// there are many possible choices for digest.
EVP_DigestInit(&md_ctx, EVP_ecdsa());
while(!feof(stdin)) {
inlen = BIO_read(bio_stdin, inbuf, 80);
if(!EVP_DigestUpdate(&md_ctx, inbuf, inlen)) {
fatalerror("EVP_DigestUpdate");
}
}
EVP_DigestFinal(&md_ctx, digest, &dgst_len);
signature = ECDSA_do_sign(digest, dgst_len, key);
digest_bn = BN_bin2bn(digest, dgst_len, NULL);
BIO_printf(bio_stderr,"SHA1: %s\n",BN_bn2hex(digest_bn));
BIO_printf(bio_stdout,"\nSignature:\n");
writekey(bio_stdout,"SIGNR: ",signature->r);
writekey(bio_stdout,"SIGNS: ",signature->s);
return 0;
}
Logged
September 15, 2007, 10:41:02 AM
therealr
Newbii
Karma: +4/-0
Offline
Join date:
September 15 2007
Posts: 9
Re: The crypto used for wii savegame files is sect233r1
Code:
/* Educational program for verifying a signature with Elliptic Curve crypto using openssl's libssl
* (c) 2007 R, Licensed under GNU GPL v3, see <http://www.gnu.org/licenses/> for details.
*
* compile with: gcc -o verify verify.c -lssl -lcrypto -Wall
*/
#include <stdlib.h>
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/ec.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ecdh.h>
#include <openssl/evp.h>
void fatalerror(char *message) {
fprintf(stderr,"\nError: %s\n",message);
fprintf(stderr,"%s\n",ERR_error_string(ERR_get_error(),NULL));
exit(1);
}
void writekey(BIO *bio,char *text,const BIGNUM *bn) {
int size;
BIO_printf(bio,text);
size = strlen(BN_bn2hex(bn));
for(;size<60;size++) {
BIO_printf(bio,"0");
}
BIO_printf(bio,"%s\n",BN_bn2hex(bn));
}
int main(int argc, char *argv[]) {
EC_KEY *key = NULL;
BIO *bio_stderr, *bio_stdin, *bio_stdout;
EC_POINT *pub_key;
const EC_GROUP *group;
BIGNUM *pub_key_x = BN_new();
BIGNUM *pub_key_y = BN_new();
EVP_MD_CTX md_ctx;
ECDSA_SIG *signature = ECDSA_SIG_new();
int ret;
unsigned char inbuf[80];
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int dgst_len = 0, inlen = 0;
SSL_library_init();
SSL_load_error_strings();
if(argc < 5) {
fprintf(stderr,"\nUsage: sign <public key x> <public key y> <signature r> <signature s>\n\n");
fprintf(stderr,"Verifies a signature for data on stdin.\n");
fprintf(stderr,"Keys are given as compound hexadecimal strings.\n");
exit(1);
}
bio_stdout = BIO_new_fp(stdout, BIO_NOCLOSE);
bio_stdin = BIO_new_fp(stdin, BIO_NOCLOSE);
bio_stderr = BIO_new_fp(stderr, BIO_NOCLOSE);
key = EC_KEY_new_by_curve_name(NID_sect233r1);
if (key == NULL) {
fatalerror("EC_KEY_new_by_curve_name");
}
ret = BN_hex2bn(&pub_key_x,argv[1]);
ret = BN_hex2bn(&pub_key_y,argv[2]) && ret;
ret = BN_hex2bn(&signature->r,argv[3]) && ret;
ret = BN_hex2bn(&signature->s,argv[4]) && ret;
if(ret == 0) {
fatalerror("Couldn't parse keys.");
}
group = EC_KEY_get0_group(key);
pub_key = EC_POINT_new(group);
if(!EC_POINT_set_affine_coordinates_GFp(group, pub_key, pub_key_x, pub_key_y, NULL)) {
fatalerror("EC_PINT_set_affine_coordinates_GFp");
}
if(!EC_KEY_set_public_key(key, pub_key)) {
fatalerror("EC_KEY_set_public_key");
}
BIO_printf(bio_stderr,"Read key data:\n");
writekey(bio_stderr,"PUBX: ",pub_key_x);
writekey(bio_stderr,"PUBY: ",pub_key_y);
BIO_printf(bio_stderr,"Read signature:\n");
writekey(bio_stdout,"SIGNR: ",signature->r);
writekey(bio_stdout,"SIGNS: ",signature->s);
if (!EC_KEY_check_key(key)) {
fatalerror("EC_KEY_check_key");
}
BIO_printf(bio_stderr,"Creating digest.\n");
EVP_MD_CTX_init(&md_ctx);
// there are many possible choices for digest.
EVP_DigestInit(&md_ctx, EVP_ecdsa());
while(!feof(stdin)) {
inlen = BIO_read(bio_stdin, inbuf, 80);
if(!EVP_DigestUpdate(&md_ctx, inbuf, inlen)) {
fatalerror("EVP_DigestUpdate");
}
}
EVP_DigestFinal(&md_ctx, digest, &dgst_len);
ret = ECDSA_do_verify(digest, dgst_len, signature, key);
if (ret == -1){
printf("Error: ECDSA_do_verify\n");
}else if (ret == 0){
printf("\nIncorrect Signature\n");
}else{
printf("\nThe Signature is CORRECT\n");
}
return 0;
}
Logged
September 15, 2007, 10:42:36 AM
therealr
Newbii
Karma: +4/-0
Offline
Join date:
September 15 2007
Posts: 9
Re: The crypto used for wii savegame files is sect233r1
Code:
/* Educational program for generating Elliptic Curve keys using openssl's libssl
* (c) 2007 R, Licensed under GNU GPL v3, see <http://www.gnu.org/licenses/> for details.
*
* compile with: gcc -o generatekey generatekey.c -l ssl -Wall
*/
#include <stdlib.h>
#include <openssl/ssl.h>
#include <openssl/ec.h>
#include <openssl/bio.h>
#include <openssl/err.h>
void fatalerror(char *message) {
fprintf(stderr,"\nError: %s\n",message);
fprintf(stderr,"%s\n",ERR_error_string(ERR_get_error(),NULL));
exit(1);
}
void writekey(BIO *bio,char *text,const BIGNUM *bn) {
int size;
BIO_printf(bio,text);
size = strlen(BN_bn2hex(bn));
for(;size<60;size++) {
BIO_printf(bio,"0");
}
BIO_printf(bio,"%s\n",BN_bn2hex(bn));
}
int main() {
EC_KEY *key = EC_KEY_new();
const BIGNUM *priv_key;
const EC_POINT *pub_key;
const EC_GROUP *group;
BIGNUM *pub_key_x = BN_new();
BIGNUM *pub_key_y = BN_new();
BIO *bio_stdout, *bio_stderr;
SSL_library_init();
SSL_load_error_strings();
bio_stdout = BIO_new_fp(stdout, BIO_NOCLOSE);
bio_stderr = BIO_new_fp(stderr, BIO_NOCLOSE);
key = EC_KEY_new_by_curve_name(NID_sect233r1);
if (key == NULL) {
fatalerror("EC_KEY_new_by_curve_name");
}
if (!EC_KEY_generate_key(key)) {
fatalerror("EC_KEY_generate_key");
}
if (!EC_KEY_check_key(key)) {
fatalerror("EC_KEY_check_key");
}
// EC_KEY_print(bio_stdout,key,0);
priv_key = EC_KEY_get0_private_key(key);
group = EC_KEY_get0_group(key);
pub_key = EC_KEY_get0_public_key(key);
if(!EC_POINT_get_affine_coordinates_GFp(group, pub_key, pub_key_x, pub_key_y, NULL)) {
fatalerror("EC_KEY_get_affine_coordinates_GFp");
}
BIO_printf(bio_stderr,"Generated key:\n");
writekey(bio_stderr,"PRIV: ",priv_key);
writekey(bio_stderr,"PUBX: ",pub_key_x);
writekey(bio_stderr,"PUBY: ",pub_key_y);
return 0;
}
Logged
September 15, 2007, 10:44:24 AM
therealr
Newbii
Karma: +4/-0
Offline
Join date:
September 15 2007
Posts: 9
Re: The crypto used for wii savegame files is sect233r1
Code:
/* Educational program for encrypting data with Elliptic Curve crypto using openssl's libssl
* (c) 2007 R, Licensed under GNU GPL v3, see <http://www.gnu.org/licenses/> for details.
*
* compile with: gcc -o encrypt encrypt.c -lssl -lcrypto -Wall
*/
#include <stdlib.h>
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/ec.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ecdh.h>
#include <openssl/evp.h>
void fatalerror(char *message) {
fprintf(stderr,"\nError: %s\n",message);
fprintf(stderr,"%s\n",ERR_error_string(ERR_get_error(),NULL));
exit(1);
}
void writekey(BIO *bio,char *text,const BIGNUM *bn) {
int size;
BIO_printf(bio,text);
size = strlen(BN_bn2hex(bn));
for(;size<60;size++) {
BIO_printf(bio,"0");
}
BIO_printf(bio,"%s\n",BN_bn2hex(bn));
}
int main(int argc, char *argv[]) {
EC_KEY *other_key = NULL;
EC_KEY *own_key = NULL;
BIO *bio_stdout, *bio_stdin, *bio_stderr;
EC_POINT *other_pub_key;
EC_POINT *own_pub_key;
const EC_GROUP *own_group;
const EC_GROUP *other_group;
BIGNUM *other_pub_key_x = BN_new();
BIGNUM *other_pub_key_y = BN_new();
BIGNUM *own_pub_key_x = BN_new();
BIGNUM *own_pub_key_y = BN_new();
BIGNUM *own_priv_key = BN_new();
BIGNUM *ecdh_bn = BN_new();
EVP_CIPHER_CTX ctx;
unsigned char ecdh_keybuffer[30];
int ret, ecdh_keylen;
unsigned char outbuf[80];
unsigned char inbuf[80];
unsigned char iv[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int outlen, inlen;
SSL_library_init();
SSL_load_error_strings();
if(argc < 6) {
fprintf(stderr,"\nUsage: encrypt <own private key> <own public key x>\n");
fprintf(stderr," <own public key y> <other's public key x> <other's public key y>\n\n");
fprintf(stderr,"Encrypts text on stdin and writes unencrypted text to stdout.\n");
fprintf(stderr,"NOTE: for decryption, your recepient needs both the encrypted data *and* your public keypair.\n");
fprintf(stderr,"Keys are given as compound hexadecimal strings.\n");
fprintf(stderr,"For base64 output:\n");
fprintf(stderr," cat plain.txt | ./encrypt [parameters] | openssl openssl base64 > encrypted.b64\n\n");
exit(1);
}
bio_stdout = BIO_new_fp(stdout, BIO_NOCLOSE);
bio_stdin = BIO_new_fp(stdin, BIO_NOCLOSE);
bio_stderr = BIO_new_fp(stderr, BIO_NOCLOSE);
BIO_printf(bio_stderr,"Reading receiver public key:\n");
other_key = EC_KEY_new_by_curve_name(NID_sect233r1);
if (other_key == NULL) {
fatalerror("EC_KEY_new_by_curve_name");
}
ret = BN_hex2bn(&other_pub_key_x,argv[4]);
ret = BN_hex2bn(&other_pub_key_y,argv[5]) && ret;
if(ret == 0) {
fatalerror("Couldn't parse receiver keys.");
}
other_group = EC_KEY_get0_group(other_key);
other_pub_key = EC_POINT_new(other_group);
if(!EC_POINT_set_affine_coordinates_GFp(other_group, other_pub_key, other_pub_key_x, other_pub_key_y, NULL)) {
fatalerror("EC_PINT_set_affine_coordinates_GFp");
}
if(!EC_KEY_set_public_key(other_key, other_pub_key)) {
fatalerror("EC_KEY_set_public_key");
}
BIO_printf(bio_stderr,"Receiver public keys:\n");
writekey(bio_stderr,"PUBX: ",other_pub_key_x);
writekey(bio_stderr,"PUBY: ",other_pub_key_y);
if (!EC_KEY_check_key(other_key)) {
fatalerror("EC_KEY_check_key");
}
BIO_printf(bio_stderr,"Reading sender private and public key:\n");
own_key = EC_KEY_new_by_curve_name(NID_sect233r1);
if (own_key == NULL) {
fatalerror("EC_KEY_new_by_curve_name");
}
ret = BN_hex2bn(&own_priv_key,argv[1]);
ret = BN_hex2bn(&own_pub_key_x,argv[2]) && ret;
ret = BN_hex2bn(&own_pub_key_y,argv[3]) && ret;
if(ret == 0) {
fatalerror("Couldn't parse sender keys.");
}
if(!EC_KEY_set_private_key(own_key, own_priv_key)) {
fatalerror("EC_KEY_set_private_key");
}
own_group = EC_KEY_get0_group(own_key);
own_pub_key = EC_POINT_new(own_group);
if(!EC_POINT_set_affine_coordinates_GFp(own_group, own_pub_key, own_pub_key_x, own_pub_key_y, NULL)) {
fatalerror("EC_PINT_set_affine_coordinates_GFp");
}
if(!EC_KEY_set_public_key(own_key, own_pub_key)) {
fatalerror("EC_KEY_set_public_key");
}
if (!EC_KEY_check_key(own_key)) {
fatalerror("EC_KEY_check_key");
}
BIO_printf(bio_stderr,"Sender public,private key:\n");
writekey(bio_stderr,"PRIV: ",own_priv_key);
writekey(bio_stderr,"PUBX: ",own_pub_key_x);
writekey(bio_stderr,"PUBY: ",own_pub_key_y);
BIO_printf(bio_stderr,"Generating ECDH key of 232 bits.\n");
ECDH_set_method(own_key, ECDH_OpenSSL());
ecdh_keylen = ECDH_compute_key(ecdh_keybuffer, 30, other_pub_key, own_key,NULL);
if(ecdh_keylen != 30) {
fatalerror("ECDH_compute_key");
}
ecdh_bn = BN_bin2bn(ecdh_keybuffer,30,NULL);
writekey(bio_stderr,"ECDH SHARED SECRET: ",ecdh_bn);
BIO_printf(bio_stderr,"Encrypting with AES 192 using bytes 7-30 of the ECDH data and iv=0 to stdout.\n");
EVP_EncryptInit(&ctx, EVP_aes_192_cbc(), ecdh_keybuffer+6, iv);
while(!feof(stdin)) {
inlen = BIO_read(bio_stdin, inbuf, 80);
if(!EVP_EncryptUpdate(&ctx, outbuf, &outlen, inbuf, inlen)){
fatalerror("EVP_encrypt_update");
}
BIO_write(bio_stdout,outbuf,outlen);
}
EVP_EncryptFinal(&ctx,outbuf, &outlen);
BIO_write(bio_stdout,outbuf,outlen);
if(BIO_flush(bio_stdout)!=1) {
fatalerror("BIO_flush");
}
return 0;
}
Logged
September 15, 2007, 10:45:31 AM
therealr
Newbii
Karma: +4/-0
Offline
Join date:
September 15 2007
Posts: 9
Re: The crypto used for wii savegame files is sect233r1
Code:
/* Educational program for decrypting data with Elliptic Curve crypto using openssl's libssl
* (c) 2007 R, Licensed under GNU GPL v3, see <http://www.gnu.org/licenses/> for details.
*
* compile with: gcc -o decrypt decrypt.c -lssl -lcrypto -Wall
*/
#include <stdlib.h>
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/ec.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ecdh.h>
#include <openssl/evp.h>
void fatalerror(char *message) {
fprintf(stderr,"\nError: %s\n",message);
fprintf(stderr,"%s\n",ERR_error_string(ERR_get_error(),NULL));
exit(1);
}
void writekey(BIO *bio,char *text,const BIGNUM *bn) {
int size;
BIO_printf(bio,text);
size = strlen(BN_bn2hex(bn));
for(;size<60;size++) {
BIO_printf(bio,"0");
}
BIO_printf(bio,"%s\n",BN_bn2hex(bn));
}
int main(int argc, char *argv[]) {
EC_KEY *other_key = NULL;
EC_KEY *own_key = NULL;
BIO *bio_stdout, *bio_stdin, *bio_stderr;
EC_POINT *other_pub_key;
EC_POINT *own_pub_key;
const EC_GROUP *own_group;
const EC_GROUP *other_group;
BIGNUM *other_pub_key_x = BN_new();
BIGNUM *other_pub_key_y = BN_new();
BIGNUM *own_pub_key_x = BN_new();
BIGNUM *own_pub_key_y = BN_new();
BIGNUM *own_priv_key = BN_new();
BIGNUM *ecdh_bn = BN_new();
unsigned char ecdh_keybuffer[30];
int ret, ecdh_keylen;
unsigned char outbuf[80];
unsigned char inbuf[80];
unsigned char iv[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int outlen, inlen;
EVP_CIPHER_CTX ctx;
SSL_library_init();
SSL_load_error_strings();
if(argc < 6) {
fprintf(stderr,"\nUsage: decrypt <own private key> <own public key x>\n");
fprintf(stderr," <own public key y> <other's public key x> <other's public key y>\n\n");
fprintf(stderr,"Decrypts text on stdin and writes cleartext to stdout.\n");
fprintf(stderr,"Keys are given as compound hexadecimal strings.\n");
fprintf(stderr,"For base64 input:\n");
fprintf(stderr," cat encrypted.b64 | openssl base64 -d | ./decrypt [parameters] > plain.txt\n\n");
exit(1);
}
bio_stdout = BIO_new_fp(stdout, BIO_NOCLOSE);
bio_stdin = BIO_new_fp(stdin, BIO_NOCLOSE);
bio_stderr = BIO_new_fp(stderr, BIO_NOCLOSE);
BIO_printf(bio_stderr,"Reading sender public key:\n");
other_key = EC_KEY_new_by_curve_name(NID_sect233r1);
if (other_key == NULL) {
fatalerror("EC_KEY_new_by_curve_name");
}
ret = BN_hex2bn(&other_pub_key_x,argv[4]);
ret = BN_hex2bn(&other_pub_key_y,argv[5]) && ret;
if(ret == 0) {
fatalerror("Couldn't parse sender keys.");
}
other_group = EC_KEY_get0_group(other_key);
other_pub_key = EC_POINT_new(other_group);
if(!EC_POINT_set_affine_coordinates_GFp(other_group, other_pub_key, other_pub_key_x, other_pub_key_y, NULL)) {
fatalerror("EC_PINT_set_affine_coordinates_GFp");
}
if(!EC_KEY_set_public_key(other_key, other_pub_key)) {
fatalerror("EC_KEY_set_public_key");
}
BIO_printf(bio_stderr,"Sender public keys:\n");
writekey(bio_stderr,"PUBX: ",other_pub_key_x);
writekey(bio_stderr,"PUBY: ",other_pub_key_y);
if (!EC_KEY_check_key(other_key)) {
fatalerror("EC_KEY_check_key");
}
BIO_printf(bio_stderr,"Reading receiver private and public key:\n");
own_key = EC_KEY_new_by_curve_name(NID_sect233r1);
if (own_key == NULL) {
fatalerror("EC_KEY_new_by_curve_name");
}
ret = BN_hex2bn(&own_priv_key,argv[1]);
ret = BN_hex2bn(&own_pub_key_x,argv[2]) && ret;
ret = BN_hex2bn(&own_pub_key_y,argv[3]) && ret;
if(ret == 0) {
fatalerror("Couldn't parse sender keys.");
}
if(!EC_KEY_set_private_key(own_key, own_priv_key)) {
fatalerror("EC_KEY_set_private_key");
}
own_group = EC_KEY_get0_group(own_key);
own_pub_key = EC_POINT_new(own_group);
if(!EC_POINT_set_affine_coordinates_GFp(own_group, own_pub_key, own_pub_key_x, own_pub_key_y, NULL)) {
fatalerror("EC_PINT_set_affine_coordinates_GFp");
}
if(!EC_KEY_set_public_key(own_key, own_pub_key)) {
fatalerror("EC_KEY_set_public_key");
}
if (!EC_KEY_check_key(own_key)) {
fatalerror("EC_KEY_check_key");
}
BIO_printf(bio_stderr,"Receiver private,public key:\n");
writekey(bio_stderr,"PRIV: ",own_priv_key);
writekey(bio_stderr,"PUBX: ",own_pub_key_x);
writekey(bio_stderr,"PUBY: ",own_pub_key_y);
BIO_printf(bio_stderr,"Generating ECDH key of 232 bits.\n");
ECDH_set_method(own_key, ECDH_OpenSSL());
ecdh_keylen = ECDH_compute_key(ecdh_keybuffer, 30, other_pub_key, own_key,NULL);
if(ecdh_keylen != 30) {
fatalerror("ECDH_compute_key");
}
ecdh_bn = BN_bin2bn(ecdh_keybuffer,30,NULL);
writekey(bio_stderr,"ECDH SHARED SECRET: ",ecdh_bn);
BIO_printf(bio_stderr,"Decrypting with AES 192 using bytes 7-30 of the ECDH data and iv=0.\n");
EVP_DecryptInit(&ctx, EVP_aes_192_cbc(), ecdh_keybuffer+6, iv);
do {
inlen = BIO_read(bio_stdin,inbuf,80);
if(!EVP_DecryptUpdate(&ctx, outbuf, &outlen, inbuf, inlen)){
fatalerror("EVP_decrypt_update");
}
BIO_write(bio_stdout,outbuf,outlen);
} while(inlen > 0 || !BIO_eof(bio_stdin) || !feof(stdin));
EVP_DecryptFinal(&ctx,outbuf, &outlen);
BIO_write(bio_stdout,outbuf,outlen);
if(BIO_flush(bio_stdout)!=1) {
fatalerror("BIO_flush");
}
return 0;
}
Logged
September 15, 2007, 10:47:39 AM
therealr
Newbii
Karma: +4/-0
Offline
Join date:
September 15 2007
Posts: 9
Re: The crypto used for wii savegame files is sect233r1
That was all for now. Sorry for the multiple posts for the different souce files, but I thought it became more structured like that. Enjoy!
//R
Logged
September 15, 2007, 11:52:03 AM
twistedsymphony
Global Mod
Super Member
Karma: +18/-1
Offline
Join date:
February 23 2007
Posts: 338
Re: The crypto used for wii savegame files is sect233r1
this is some interesting info... most of it is above my head (security/encryption is mostly Greek to me)
Any idea where the public key is located and if it would be possible to extract it?
Logged
September 16, 2007, 10:00:10 AM
m3rc3r
Newbii
Karma: +0/-0
Offline
Join date:
September 16 2007
Posts: 1
Re: The crypto used for wii savegame files is sect233r1
I'm guessing that you have PIC or some other programmable interface hooked up to be able to see this. Would it be possible for you to try some sort of a man-in-the-middle attack for the key exchange scheme ? That looks like the weakest spot. Might give some insight on the 233-bit integers. Just my 2 cents.
Logged
September 18, 2007, 11:00:37 AM
PaceMaker
Newbii
Karma: +0/-0
Offline
Join date:
September 18 2007
Posts: 1
Re: The crypto used for wii savegame files is sect233r1
For what it's worth, I've verified this to be true for the last hash (hash6). See this page for a description of the save games:
http://wiibrew.org/index.php?title=Wii_Savegame_Parser
For some reason other similar hashes (hash3 and hash5) don't show up as valid keys. I don't know if it's a parsing problem or if they aren't really similar hashes.
-- PaceMaker
Logged
September 29, 2007, 12:20:16 PM
therealr
Newbii
Karma: +4/-0
Offline
Join date:
September 15 2007
Posts: 9
Re: The crypto used for wii savegame files is sect233r1
Sorry for the obvious typo in the original post:
"The number pairs are stored as a compound 60 (bit -> byte) data."
(Typical that this is the one sentence that travels around the world...)
@PaceMaker: Re-read my outline of the certificate format. Some of your 'hash:es' are public key-pairs, others are signature-pairs. You can only verify the ones that are public key-pairs with EC_KEY_check_key. Openssl doesn't appear to have any function similar to EC_KEY_check_key that test if two numbers are a proper signature-pair on the sect233r1 curve; but maybe such a test can be created. The only "test" I currently know that surely works is to actually verify the signature (see the 'verify' program), but this is harder to do, since it requires you to know what has been signed, and with which message digest; I know neither at this point. If I read the wiibrew page correctly, their hash 4 and 6 refer to the certificate keys, the other hashes refer to signatures.
To clarify other discussion: the posted information does not really "enable homebrew". However, I think that the hypothetical scenario that some people hint at for 'an attacker' to make the Wii run own code is:
1. Find out savegame format and encryption format.
2. "Search" through the internals of the Wii (firmware, flash memory, encryption chips?) to find the private keys used to encrypt saves. (must be in there *somewhere*)
3. Now altered savegame data can be encrypted and passed to games.
4. Search for a game that does funny things when loading an altered save.
5. Use ordinary software vulnerability techniques to run own code.
I saw a comment elsewhere that the information posted above just 'possibly enables the same thing as the Datel Powersaves product'. I looked up the product and was surprised. Apparently they provide a number of pre-hacked saves that can be loaded by the respective games. Does anyone know how they did this? I can see only two options: Either they figured out the save format themselves and are already on step 3 above -- or -- they have some kind of deal with Nintendo over this. However, as far as I understand, the product currently does not allow users to alter savegame data themselves.
Some more insight about how 'an attacker' may approach step 2 above: the 'checkkey' program previously posted demonstrates how to match a 233 bit private key number with a pair of two 233-bit public key numbers. It is also known that keys are 29 byte + 1 bit long, and thus, if stored unencrypted, the first byte will be 00 or 01.
//R
Logged
September 30, 2007, 08:46:17 AM
twistedsymphony
Global Mod
Super Member
Karma: +18/-1
Offline
Join date:
February 23 2007
Posts: 338
Re: The crypto used for wii savegame files is sect233r1
This is the personal blog of one of the powersaves developers:
http://jayfng.spaces.live.com/blog/cns
!A5557A058F6EA78B!1642.entry
maybe you could send him an email and just ask him
Logged
October 11, 2007, 06:22:19 AM
covox
Newbii
Karma: +0/-0
Offline
Join date:
October 11 2007
Posts: 1
Re: The crypto used for wii savegame files is sect233r1
That's quite awesome, knowing there's formatted key data in the tail of the encryption.
I poked around in the released dump of the PAL flash memory. There appears to be two identical, interesting fragments (offset 0x20000 to 0x20F00, offset 0xE0000 to 0xE0F00); they contain hashes along with fragments of Root-CA00000001 bollocks. Sadly, none appear to be the sect233r1 keylength of 30 bytes, the majority are around 256 bytes long. These sections are the only parts of the dump where the certificate string "Root" appears in plaintext. Immediately after (offset 0x20F00 to 0x30000, offset 0xE0F00 to 0x100000) is encrypted data, but it is identical in both cases.
Not sure if you've seen it or not, but
it could contain something.
Logged
Pages: [
1
]
« previous
next »
Jump to:
Please select a destination:
-----------------------------
General
-----------------------------
=> Member Submitted News
=> Newbii Chat
=> Comments/Suggestions
-----------------------------
Wii Forums
-----------------------------
=> Wii General Chat
=> Wii Modchips/Softmods
===> General Modchip/Softmod Discussion
===> Chiip
===> Cyclowiz
===> D2Pro / D2CKey
===> D2Sun
===> DriveKey
===> Flatmod
===> InFeCtuS
===> OpenWii / Wiip
===> W4Pro
===> Wasabi
===> Wii-Boss
===> WiiFree
===> WiiJii
===> Wiikey
===> Wiikey 2
===> Wiinja
===> WiiWasp
===> YAOSM
=> Wii Case/Hardware Mods
===> Wii Remote Hacking
=> Wii Repair/Support
=> Wii Backups
=> Wii Homebrew
===> Native Wii Homebrew
===> Gamecube Mode Homebrew
===> Internet Channel Homebrew
===> Wii PC Tools
=> Wii Game Chat
===> Virtual Console Chat
=> Wii Technical Hacking Discussion
-----------------------------
DS Forums
-----------------------------
=> DS/DSi General Chat
=> DS Flashcards/ROMs
===> General DS Flashcart Discussion
===> AceKard / AceKard R.P.G.
===> CycloDS Evolution
===> DS-Xtreme
===> EZ Flash V
===> G6 / M3 DS Real
===> M3 DS Simply / R4 DS
===> SuperCard DS (One)
===> TopToyDS
=> DS Case/Hardware Mods
=> DS Repair/Support
=> DS Homebrew
===> DS PC Tools
=> DS Game Chat
-----------------------------
Other Consoles
-----------------------------
=> GC General Chat
===> GC Modchips/Softmods
===> GC Case/Hardware Mods
===> GC Repair/Support
===> GC Backups
===> GC Homebrew
===> GC Game Chat
=> GB/GBA General Chat
===> GB/GBA Game Chat
===> GB/GBA Homebrew
===> GB/GBA Reapair & Support
===> GB/GBA Case & Hardware Mods
===> GB/GBA Flashcards & Roms
=> N64 General Chat
=> SNES General Chat
=> NES General Chat
=> Non-Nintendo Consoles
===> Microsoft-Scene
===> Sony-Scene
-----------------------------
Shopping Forums
-----------------------------
=> Buy/Sell/Trade
===> General B/S/T
===> Game Trades
=> Installers/Service Providers
=> Webshop Ratings
-----------------------------
Off-Topic
-----------------------------
=> Entertainment
=> Personal Computer and Electronics
=> Sports
=> Unintelligible Chatter
Loading...