Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: Diffie algorithm in openssl: and Java

245 views
Skip to first unread message

azhar jodatti

unread,
Mar 18, 2013, 2:26:54 AM3/18/13
to


​Thanks matt for looking at this. below are the details

json  from C with openSSL

{
    "prime": "B01DBDE7823A696F13EEFDE810DF2A010ED8BA919186029BEECCF2F0454CE85CA3E3FFD0EB3A578F80C28930AD98559D57605E37BFE2B1BD3C6D6C7657384F4DDFF45D57C59EF2DEADAF7605A1EB36A5D5007162F026E5AE161F489C8C79A5AD10C40FC7B914CDD85EE8A493307EE183194655D5190A3B7D8B45036E56E0C653",
    "basegenerator": "2",
    "size": "1024",
    "publickey": "829DE389D7731F6CB1C92B92965E119FFCBAE433C5B19B5C262623FD5EA6F2D53EFAD3195372B7C746DB376C3739CBC03BE7614183F658E059F02FF8C463051E3684424BE8F3F96353275201D8B8154DED3A5152DD04EBD55C0EC20544F975EEEB703B3085C174C761712AC83EACF8507895571E1F076876F26162504D75EF11"
}


JSON with JAVA

{
    "prime": "178011905478542266528237562450159990145232156369120674273274450314442865788737020770612695252123463079567156784778466449970650770920727857050009668388144034129745221171818506047231150039301079959358067395348717066319802262019714966524135060945913707594956514672855690606794135837542707371727429551343320695239",
    "basegenerator": "174068207532402095185811980123523436538604490794561350978495831040599953488455823147851597408940950725307797094915759492368300574252438761037084473467180148876118103083043754985190983472601550494691329488083395492313850000361646482644608492304078721818959999056496097769368017749273708962006689187956744210730",
    "size": "1024",
    "publickey": "154098060632197825972569070553594673213907981120204558893455132154488920498286340180930009617674527453058248409146259055129616519883338912429359077804301589391083095780370584174889589223725092053310001148182587778315708960959816212553890780658697750126252666385136330617189340099488509957293788029153796583284280546893194823052732368554200517384648060949814219845513312636361799960550824305241776726569729968117653644039260346804354135691237238964153781814300021332541328282477027772784043832083697573459487287571520026609334964134811373470209956613009283464376018849091639198208244682804180475479662224652170610412421382256896232908714139611606796633319949985382724877107919957408909942743414340389890006834786464852247662337830546584844189278383274479199021252090407963572739286575933788241737975537671923484277171204499262529715278092506505239752566691287452373502190399117732855968397767896906732126573639005461407592315315318920060328019073971670048355762952267750188451524151795498747866082848788789357672209810743252483"
}


Kindly let me know if you need anything else. even I can share my implementation (both Java and C)



Regards,
Azhar



On Sun, Mar 17, 2013 at 1:10 PM, Matt Caswell <fr...@baggins.org> wrote:


On 16 March 2013 22:29, azhar jodatti <azha...@gmail.com> wrote:

Matt,

No reason as such for using low level interface.I just want to get it done. Do you see any issues with low level interface? or any issues with my code?

In addition, the server and client works over REST API's, hence I am using JSON format to pass the parameter over the wire.

The low-level interface will *work*, its just *better* to use the high level interface. The high level interface is less tightly coupled to the specifics of any one particular algorithm (you would be able to reuse much of your code if you needed to use ECDH instead of DH at some point in the future). In general the high level interface also hides much of the complexity of working with specific algorithms.

Can you supply a sample of the JSON format that you are using to pass parameters and public keys?

Matt


azhar jodatti

unread,
Mar 18, 2013, 8:15:10 AM3/18/13
to


​1) The C version is in hex while the java version is in decimal. Is this intentional? When you are reading in the values are reading them correctly (i.e. as hex or as decimal as required)
Yes. it was intentional. I am taking care of this.
2) Is this sample from the *same* key exchange? The parameters are different which are obviously going to cause it to fail.
When I run both programs it calculates the params (p,g,pk) every time on execution . that's the reason both key values are different. That won't make any such difference :) right?

3) Its not actually necessary to pass the full parameters every time you exchange keys. This can be agreed up front, e.g. RF5114 defines a set of standard well known parameters which can be used "off the shelf". OpenSSL has built-in support for these.
I need to look into this. Do you mean the hard coded prime and base generator numbers at client and server? how about public key? 


Regards,
Azhar



On Mon, Mar 18, 2013 at 3:22 PM, Matt Caswell <fr...@baggins.org> wrote:


On 18 March 2013 06:26, azhar jodatti <azha...@gmail.com> wrote:


Thanks matt for looking at this. below are the details

json  from C with openSSL

{
    "prime": "B01DBDE7823A696F13EEFDE810DF2A010ED8BA919186029BEECCF2F0454CE85CA3E3FFD0EB3A578F80C28930AD98559D57605E37BFE2B1BD3C6D6C7657384F4DDFF45D57C59EF2DEADAF7605A1EB36A5D5007162F026E5AE161F489C8C79A5AD10C40FC7B914CDD85EE8A493307EE183194655D5190A3B7D8B45036E56E0C653",
    "basegenerator": "2",
    "size": "1024",
    "publickey": "829DE389D7731F6CB1C92B92965E119FFCBAE433C5B19B5C262623FD5EA6F2D53EFAD3195372B7C746DB376C3739CBC03BE7614183F658E059F02FF8C463051E3684424BE8F3F96353275201D8B8154DED3A5152DD04EBD55C0EC20544F975EEEB703B3085C174C761712AC83EACF8507895571E1F076876F26162504D75EF11"
}


JSON with JAVA

{
    "prime": "178011905478542266528237562450159990145232156369120674273274450314442865788737020770612695252123463079567156784778466449970650770920727857050009668388144034129745221171818506047231150039301079959358067395348717066319802262019714966524135060945913707594956514672855690606794135837542707371727429551343320695239",
    "basegenerator": "174068207532402095185811980123523436538604490794561350978495831040599953488455823147851597408940950725307797094915759492368300574252438761037084473467180148876118103083043754985190983472601550494691329488083395492313850000361646482644608492304078721818959999056496097769368017749273708962006689187956744210730",
    "size": "1024",
    "publickey": "154098060632197825972569070553594673213907981120204558893455132154488920498286340180930009617674527453058248409146259055129616519883338912429359077804301589391083095780370584174889589223725092053310001148182587778315708960959816212553890780658697750126252666385136330617189340099488509957293788029153796583284280546893194823052732368554200517384648060949814219845513312636361799960550824305241776726569729968117653644039260346804354135691237238964153781814300021332541328282477027772784043832083697573459487287571520026609334964134811373470209956613009283464376018849091639198208244682804180475479662224652170610412421382256896232908714139611606796633319949985382724877107919957408909942743414340389890006834786464852247662337830546584844189278383274479199021252090407963572739286575933788241737975537671923484277171204499262529715278092506505239752566691287452373502190399117732855968397767896906732126573639005461407592315315318920060328019073971670048355762952267750188451524151795498747866082848788789357672209810743252483"
}


Kindly let me know if you need anything else. even I can share my implementation (both Java and C)

So a few things strike me about this:

1) The C version is in hex while the java version is in decimal. Is this intentional? When you are reading in the values are reading them correctly (i.e. as hex or as decimal as required)

2) Is this sample from the *same* key exchange? The parameters are different which are obviously going to cause it to fail.

3) Its not actually necessary to pass the full parameters every time you exchange keys. This can be agreed up front, e.g. RF5114 defines a set of standard well known parameters which can be used "off the shelf". OpenSSL has built-in support for these.

Matt

 

Matt Caswell

unread,
Mar 18, 2013, 9:17:10 AM3/18/13
to
On 18 March 2013 12:15, azhar jodatti <azha...@gmail.com> wrote:
2) Is this sample from the *same* key exchange? The parameters are different which are obviously going to cause it to fail.
When I run both programs it calculates the params (p,g,pk) every time on execution . that's the reason both key values are different. That won't make any such difference :) right?

The parameters p, q and g need to be the same on both sides of the exchange. The values for this can be agreed in advance. You do not need to calculate them every time. If the two parties in the exchange are using different parameters then it will not work. Each side will have different private keys, and hence different public keys. You *can* generate the parameters every time - it will work as long as both sides are using the same p, q and g values - but there is no reason to do so.

I also just noticed that in your JSON sample there is only one prime number provided. There are in fact two required: p and q.
 

3) Its not actually necessary to pass the full parameters every time you exchange keys. This can be agreed up front, e.g. RF5114 defines a set of standard well known parameters which can be used "off the shelf". OpenSSL has built-in support for these.
I need to look into this. Do you mean the hard coded prime and base generator numbers at client and server? how about public key? 

The values p, q and g can be hard coded at client and server. The private/public keys can also be static on both sides of the exchange - but if you do so then bear in mind that the agreed on secret will be the same every time. More likely you will want to use ephemeral mode - one side (usually the server) can have a static private/public key, whilst the client will use a new one every time. This will ensure that a new secret is agreed each time.

One other point to make here is that it looks very much like you are designing your own protocol rather than implementing a well defined one. This is fraught with security risks....it is very easy to make a mistake - and is generally a bad idea. Use standardised approaches where ever possible. In particular note that the diffie-hellman implementation in use here provides a "raw" shared secret at the end. Standardised protocols normally define a process for turning that shared secret into something which can be used as a key (typically by passing the secret, along with other data through some message digest). E.g. see RFC 2631

Matt
 

Matt Caswell

unread,
Mar 18, 2013, 11:32:00 AM3/18/13
to
On 18 March 2013 15:05, azhar jodatti <azha...@gmail.com> wrote:

I also just noticed that in your JSON sample there is only one prime number provided. There are in fact two required: p and q.
well, I think other prime number is g and not q. other prime number is base generator i.e g in above JSON sample.

No, g is the generator and I don't believe there is a requirement for it to be prime. In fact your Java version of your JSON has a generator which is clearly NOT prime - it is an even number. You are missing a parameter from your JSON.

 

One other point to make here is that it looks very much like you are designing your own protocol rather than implementing a well defined one. This is fraught with security risks....it is very easy to make a mistake - and is generally a bad idea. Use standardised approaches where ever possible. In particular note that the diffie-hellman implementation in use here provides a "raw" shared secret at the end. Standardised protocols normally define a process for turning that shared secret into something which can be used as a key (typically by passing the secret, along with other data through some message digest). E.g. see RFC 2631


I don't feel i am trying to design my own protocol. at least it won't look so for me :) I want to use symmetric key encryption and for that I need a same secret key at both the ends at run time. Who else does this better than Diffie Hellman? :) :) 



Diffie Hellman is the algorithm, the protocol is about how you implement and use that algorithm, e.g. taking a ridiculous example you can use the diffie-hellman algorithm and then make it insecure by transmitting the private key in the clear in the protocol!!

See the top answer here:
http://security.stackexchange.com/questions/2202/lessons-learned-and-misconceptions-regarding-encryption-and-cryptology

Also:
http://www.cse.chalmers.se/edu/year/2012/course/TDA601/Project/Presentations06/9.pdf

And:
"Cryptographic protocols and algorithms are difficult to get right, so do not create your own"
http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/crypto.html

Matt

 

Matt Caswell

unread,
Mar 18, 2013, 5:44:12 PM3/18/13
to
On 18 March 2013 21:02, Dave Thompson <dtho...@prinpay.com> wrote:
>I also just noticed that in your JSON sample there is only one
>prime number provided. There are in fact two required: p and q.

No. *DSA* uses p,q,g. DH requires p,g which effectively determines
q, but DH computation doesn't use q and standard formats don't have
it. DH can use l which is the *size* of q thus the (max) entropy
of the agreement. It is sometimes convenient to use DSA parameters
as DH parameters by ignoring q except optionally its size.

Not entirely correct. I've just been digging into this when I saw your email. PKCS 3 does not use q for DH:
DHParameter ::= SEQUENCE {
  prime INTEGER, -- p
  base INTEGER, -- g
  privateValueLength INTEGER OPTIONAL }

However, the newer X9.42 DOES require q to be present:
DomainParameters ::= Sequence { p INTEGER, -- odd prime, p = jq+1 g INTEGER, -- generator, g^q = 1 mod p q INTEGER, -- prime factor of p-1 j INTEGER OPTIONAL, -- cofactor, j>=2 validationParms ValidationParms OPTIONAL } ValidationalParms ::= Sequence { seed BITSTRING, -- seed for prime generation pGenCounter INTEGER, -- parameter verification }

However, it seems that OpenSSL does not support the X9.42 version.
From the notes on the dhparam man page:
"OpenSSL currently only supports the older PKCS#3 DH, not the newer X9.42 DH."

All the OpenSSL built-in RFC5114 domain parameters are also defined in terms of
p, q and g.

However, you are correct that the DH computation does not use q, although I do not
know whether JCE requires it to be specified (not having used JCE).

Matt



Matt Caswell

unread,
Mar 18, 2013, 5:58:19 PM3/18/13
to
On 18 March 2013 21:44, Matt Caswell <fr...@baggins.org> wrote:
However, you are correct that the DH computation does not use q, although I do not
know whether JCE requires it to be specified (not having used JCE).

One other point on this - X9.42 describes an optional validation procedure which does use q.  From RFC2631 (based on X9.42):
   The following algorithm MAY be used to validate a received public key
   y.

     1. Verify that y lies within the interval [2,p-1]. If it does not,
        the key is invalid.
     2. Compute y^q mod p. If the result == 1, the key is valid.
        Otherwise the key is invalid.

   The primary purpose of public key validation is to prevent a small
   subgroup attack [LAW98] on the sender's key pair. If Ephemeral-Static
   mode is used, this check may not be necessary. See also [P1363] for
   more information on Public Key validation.
Matt

azhar jodatti

unread,
Mar 19, 2013, 5:01:08 AM3/19/13
to


​<--

And possibly relevant here, the standard Suncle JCE provider actually
uses DSA paramgen for DH and thus imposes the DSA size restrictions
on DH -- 512 to 1024 in steps of 64 -- although they aren't required
by any standard I know of. I don't recall if JCE also restricts
*existing* (received) params; I'll test when I have some time.
I do recall you can get around this by using BouncyCastle instead.
But just using 1024 is easy and fine.
-->

sometime I get below error "Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)"
when i use small prime numbers.It means JCE uses DSA paramateres for DH algorithm. what is openSSL equalent to this?

        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH");
        kpg.initialize(1024);
        keyPair = kpg.generateKeyPair();
           
        DHParameterSpec dhSpec = ((DHPublicKey) keyPair.getPublic()).getParams();
        baseGenerator = dhSpec.getG();
        prime = dhSpec.getP();
        sizeInBits = dhSpec.getL();
is this java code equalent to below c code?
        DH_generate_parameters_ex(client,1024,DH_GENERATOR_5,NULL);

see, with openSSL I have to pass DH_GENERATOR which only allowes (2 and 5) but that is not required in JAVA version.It generates it own base generator.
 
<--
you don't need to *generate* new parameters every time. If you do,
you must send them. Sending in standard X509-ki format is often
the easiest way (and JCE does by default) but not the only way.
-->
Do I need to do this conversion explicitly? if yes then can you please tell me how to do that.  when I generate keys using DH_generate_key() function, what is the format of the keys? If it generates according to X509 spec then X509EncodedKeySpec should work in JAVA. but that is not the case. Do you see anything regarding format here which makes this all stuff crapy and non-working?
<--
if you reuse parameters, you don't *need* to send them, but it
can be useful if you do because both parties can check they agree
and something hasn't gotten misconfigured or out of sync.
-->
Even I tried by hardcoding the C generated parameter with JAVA. still faces the same issue. :(​

Regards,
Azhar

Matt Caswell

unread,
Mar 19, 2013, 5:28:38 AM3/19/13
to
On 19 March 2013 09:01, azhar jodatti <azha...@gmail.com> wrote:

> And possibly relevant here, the standard Suncle JCE provider actually
> uses DSA paramgen for DH and thus imposes the DSA size restrictions
> on DH -- 512 to 1024 in steps of 64 -- although they aren't required
> by any standard I know of. I don't recall if JCE also restricts
> *existing* (received) params; I'll test when I have some time.
> I do recall you can get around this by using BouncyCastle instead.
> But just using 1024 is easy and fine.
> -->
>
> sometime I get below error "Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)"
> when i use small prime numbers.It means JCE uses DSA paramateres for DH algorithm. what is openSSL equalent to this?
>
> KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH");
> kpg.initialize(1024);
> keyPair = kpg.generateKeyPair();
>
> DHParameterSpec dhSpec = ((DHPublicKey) keyPair.getPublic()).getParams();
> baseGenerator = dhSpec.getG();
> prime = dhSpec.getP();
> sizeInBits = dhSpec.getL();
> is this java code equalent to below c code?
> DH_generate_parameters_ex(client,1024,DH_GENERATOR_5,NULL);
>
> see, with openSSL I have to pass DH_GENERATOR which only allowes (2 and 5) but that is not required in JAVA version.It generates it own base generator.

It appears to be equivalent, although I am not familiar with the JCE
API. What I do not understand though is why you have code to generate
parameters on *both* sides of your communication. If you are going to
generate params every time (which both Dave and myself have advised
against - it is an expensive operation), you still only need to do it
on one side of the communication. So, after a bit of googling, I
would expect to see something like this on the Java side (if the C
side generates the params):

KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH");
kpg.initialize(new DHParameterSpec(/* p value passed from C */, /* g
value passed from C */));
keyPair = kpg.generateKeyPair();

Matt
______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List openss...@openssl.org
Automated List Manager majo...@openssl.org

azhar jodatti

unread,
Mar 19, 2013, 6:37:07 AM3/19/13
to

Well, above both the code snaps are at client side, not at server. I understand I don't have to generate keys at both the end. I just wanted to give you an idea how I am doing it in JAVA and C to generate the keys. As you said both code appears to be equivalent but practically it won't seems like . at-least in my scenario. because parameters generated with above java code works with my server but that's not the case with parameters generated with above C code.
 

KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH");
kpg.initialize(new DHParameterSpec(/* p value passed from C */, /* g
value passed from C */));
keyPair = kpg.generateKeyPair();

yes, I m doing this at server. after generating keyPair I am generating keyAgreent as well
. below is the code for this

        KeyAgreement keyAgree = KeyAgreement.getInstance("DH");
        keyAgree.init(keyPair.getPrivate());

        //this generates public key at server
        byte[] serverPubKeyEnc = keyPair.getPublic().getEncoded();
​       //I really don't know how exactly it does this. but its mandatory
        keyAgree.doPhase(clientPubllicKey, true);
       //this generates secret key at server
​       byte[] sharedSecret = keyAgree.generateSecret();​

 
Matt

Matt Caswell

unread,
Mar 19, 2013, 7:23:26 AM3/19/13
to
Can you share the code where you load the parameters from the C into
JCE? Also how you set up clientPublicKey. Finally would be useful if
you can dump out the parameters after they have been read, and compare
to the JSON sent.

azhar jodatti

unread,
Mar 19, 2013, 8:22:34 AM3/19/13
to


Well, to roll out the possibility of network error's, JSON values not being passed properly and blah blah blah I just dropped that approach. instead of that I am running C program which prints the prime,generator and public key. I have another program on same machine which is written in java where I am hard coding these C generated values and trying to get the public and secret key. ofcourse it is also giving me the same exception.

below is the complete C code written to generate DH params. most of the part  is taken from openSSL library source code.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/dh.h>
#include <err.h>

static const char rnd_seed[] = "string to make the random number generator think it has the entropy";

int main(){

    BN_GENCB _cb;
    DH *client= NULL;
    char buf[12];
    unsigned char *clientbuf=NULL;
    int i,clientlen,clientout,ret=1;
    BIO *out;
   
    CRYPTO_malloc_debug_init();
        CRYPTO_dbg_set_options(V_CRYPTO_MDEBUG_ALL);
        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
    ERR_load_crypto_strings();
    #ifdef OPENSSL_SYS_WIN32
        CRYPTO_malloc_init();
    #endif
   
    RAND_seed(rnd_seed, sizeof rnd_seed);

    out=BIO_new(BIO_s_file());
        if (out == NULL) {
        printf("BIO is null. exiting from program");
        goto err;
    }
        BIO_set_fp(out,stdout,BIO_NOCLOSE);
   
    //BN_GENCB_set(&_cb,&cb, out);//is this really required. my gcc not recognizing cb instance so   just commenting
    client = DH_new();
    if(client == NULL){
        printf("Client DH is null");
        goto err;
    }
   
    DH_generate_parameters_ex(client,1024,DH_GENERATOR_5,NULL);
   
    if (!DH_check(client, &i)) {
        goto err;
    }
       
    if (i & DH_CHECK_P_NOT_PRIME)
                BIO_puts(out, "p value is not prime\n");
        if (i & DH_CHECK_P_NOT_SAFE_PRIME)
                BIO_puts(out, "p value is not a safe prime\n");
        if (i & DH_UNABLE_TO_CHECK_GENERATOR)
                BIO_puts(out, "unable to check the generator value\n");
        if (i & DH_NOT_SUITABLE_GENERATOR)
                BIO_puts(out, "the g value is not a generator\n");

        BIO_puts(out,"\np=");//this prints the P in hex
        printf("%s",BN_bn2dec(client->p));//this prints the P in decimal
        BIO_puts(out,"\ng=");
        BN_print(out,client->g);//prints generator which is 5 in this case
        BIO_puts(out,"\n");

    if (!DH_generate_key(client)) {
        printf("unable to generate client keys");
        goto err;
    }
        BIO_puts(out,"pri 1=");
        BN_print(out,client->priv_key);//prints private key
        BIO_puts(out,"\npub 1=");
        printf("%s",BN_bn2dec(client->pub_key));//prints public key in decimal format
        DH *temp = DHparams_dup(client);
       BIO_puts(out,"\n\n\n PEM = ");
       PEM_write_bio_DHparams(out, temp);//this prints public key in base64 (this is what i think :) )

    BIO_puts(out,"\n\n");
   
err:
    if (clientbuf != NULL) OPENSSL_free(clientbuf);
        if (serverbuf != NULL) OPENSSL_free(serverbuf);
        if(server != NULL) DH_free(server);
        if(client != NULL) DH_free(client);
        BIO_free(out);
    return 1;   

}

This is what it prints when I ran this program.

p=106824077746282794452228647025839229808074839339760371103063155402464842614962676228255294325459053774613506891207056818441720848774298482866918174271328357364028843638451324415691330056638482781344307395975948664971732094293996189467599104442989563027727348339786810653279203313302815966250977426622843204103
g=5
pri1=622BBB2CA70FC8665F9EC3A95CF7B5C46D2F77AB10AA7D3FF485ADA9C6E005C7CF35AC0DBBFC256D2EB3AC702899140369433E1546B9DC915ACA5883D91F8FACB731F745B23C3A399FAFBDC6355E3D4203462432E950670297F6930B98C261A215053164893C2FAB55A1170699C3EDE919E59F895455B995A19C37670A6FA358
pub1=4373485839237796166699589228729451887524557806298817546317652313209684941935291316056752499275686842785989445002203537603465313281932431907074220666705812428468899520395399424699433568818334649395647035588736697462362131440308900155995886437558059484184376957451229991382889256903754886307405909744230582829
PEM = -----BEGIN DH PARAMETERS-----
MIGHAoGBAJgfXoi5POaY+aWtOFfykV7i9JNaX1ecr1W/PeqNwpcdTg1y75FaJwrO
LZSKds6dr6HtTEs5Jltda1GY2HklY8f3mja5EhNeLGLRfchQ8+Bn2FPGU1mMFpbF
07/tRJe6SOLfbQzIcTLn+TXbkS5fKWqerRnww4NZI0B+FBC+/DIHAgEF
-----END DH PARAMETERS-----

Here is my java code .

import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.*;
import java.security.interfaces.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.interfaces.*;
import com.sun.crypto.provider.SunJCE;

public class DiffieHellmanServer {

    private DiffieHellmanServer() {
    };

    public static void main(String argv[]) {
        try {
            DiffieHellmanServer keyAgree = new DiffieHellmanServer();
            keyAgree.run1();
        }
        catch (Exception e) {
            System.err.println("Error: " + e);
            System.exit(1);
        }
    }

    private void run1() throws Exception {

        DHParameterSpec dhSkipParamSpec;

        /** using C passed hard coded parameters*/

        dhSkipParamSpec = new DHParameterSpec(skip1024Modulus,skip1024Base, 1024);
       
        /*
        Instead of base64,Even I tried with passing HEX and DECIMAL values as a client public key and then converting them into byte[]. didn't work
        */               
        byte[] clientPubKeyEnc =new sun.misc.BASE64Decoder().decodeBuffer("MIGHAoGBAJgfXoi5POaY+aWtOFfykV7i9JNaX1ecr1W/PeqNwpcdTg1y75FaJwrO"+
                                        "LZSKds6dr6HtTEs5Jltda1GY2HklY8f3mja5EhNeLGLRfchQ8+Bn2FPGU1mMFpbF"+
                                        "07/tRJe6SOLfbQzIcTLn+TXbkS5fKWqerRnww4NZI0B+FBC+/DIHAgEF");
           
           KeyFactory bobKeyFac = KeyFactory.getInstance("DH");
       
       
          X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(clientPubKeyEnc);
          PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec); // this throws invalidKeySpecException : invalid key specification
         

        /*
         * Bob gets the DH parameters associated with Alice's public key. He
         * must use the same parameters when he generates his own key pair.
         */

        DHParameterSpec dhParamSpec = ((DHPublicKey) alicePubKey).getParams();

        /** Bob creates his own DH key pair */

        KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH");
        bobKpairGen.initialize(dhParamSpec);
        KeyPair bobKpair = bobKpairGen.generateKeyPair();

        /** Bob creates and initializes his DH KeyAgreement object */

        KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH");
        bobKeyAgree.init(bobKpair.getPrivate());

        /** Bob encodes his public key, and sends it over to Alice. */

        byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();


        bobKeyAgree.doPhase(alicePubKey, true);

        byte[] bobSharedSecret = bobKeyAgree.generateSecret();

        /** print down Bob's shared key */

        bobKeyAgree.doPhase(alicePubKey, true);
        SecretKey bobDesKey = bobKeyAgree.generateSecret("DES");
        byte[] encodedKeybob = bobDesKey.getEncoded();
        System.out.println(new BigInteger(encodedKeybob));
    }

    private static final BigInteger skip1024Modulus = new BigInteger(
            "106824077746282794452228647025839229808074839339760371103063155402464842614962676228255294325459053774613506891207056818441720848774298482866918174271328357364028843638451324415691330056638482781344307395975948664971732094293996189467599104442989563027727348339786810653279203313302815966250977426622843204103");
    /** The base used with the SKIP 1024 bit modulus */
    private static final BigInteger skip1024Base = BigInteger.valueOf(5);
}







Regards,
Azhar

Matt Caswell

unread,
Mar 19, 2013, 8:54:36 AM3/19/13
to
On 19 March 2013 12:22, azhar jodatti <azha...@gmail.com> wrote:
> PEM_write_bio_DHparams(out, temp);//this prints public key in base64
> (this is what i think :) )

This is NOT a base64 representation of the public key. This is
printing out the parameters only (which does not include the public
key)


> X509EncodedKeySpec x509KeySpec = new
> X509EncodedKeySpec(clientPubKeyEnc);
> PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec); //
> this throws invalidKeySpecException : invalid key specification
>

Instead of above, try something like this:

BigInteger y = new
BigInteger("4373485839237796166699589228729451887524557806298817546317652313209684941935291316056752499275686842785989445002203537603465313281932431907074220666705812428468899520395399424699433568818334649395647035588736697462362131440308900155995886437558059484184376957451229991382889256903754886307405909744230582829");
BigInteger p = new
BigInteger("106824077746282794452228647025839229808074839339760371103063155402464842614962676228255294325459053774613506891207056818441720848774298482866918174271328357364028843638451324415691330056638482781344307395975948664971732094293996189467599104442989563027727348339786810653279203313302815966250977426622843204103");
BigInteger g = new BigInteger("5");
DHPublicKeySpec dhKeySpec = new DHPublicKeySpec(y, p, g);
PublicKey alicPubKey = bobKeyFac.generatePublic(dhKeySpec);

azhar jodatti

unread,
Mar 19, 2013, 10:18:23 AM3/19/13
to
On Tue, Mar 19, 2013 at 6:24 PM, Matt Caswell <fr...@baggins.org> wrote:
On 19 March 2013 12:22, azhar jodatti <azha...@gmail.com> wrote:
>        PEM_write_bio_DHparams(out, temp);//this prints public key in base64
> (this is what i think :) )

This is NOT a base64 representation of the public key. This is
printing out the parameters only (which does not include the public
key)


>           X509EncodedKeySpec x509KeySpec = new
> X509EncodedKeySpec(clientPubKeyEnc);
>           PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec); //
> this throws invalidKeySpecException : invalid key specification
>

What is the reason behind this? Why it won't work with X509EncodedKeySpec?
 
Instead of above, try something like this:

BigInteger y = new
BigInteger("4373485839237796166699589228729451887524557806298817546317652313209684941935291316056752499275686842785989445002203537603465313281932431907074220666705812428468899520395399424699433568818334649395647035588736697462362131440308900155995886437558059484184376957451229991382889256903754886307405909744230582829");
BigInteger p = new
BigInteger("106824077746282794452228647025839229808074839339760371103063155402464842614962676228255294325459053774613506891207056818441720848774298482866918174271328357364028843638451324415691330056638482781344307395975948664971732094293996189467599104442989563027727348339786810653279203313302815966250977426622843204103");
BigInteger g = new BigInteger("5");
DHPublicKeySpec dhKeySpec = new DHPublicKeySpec(y, p, g);
PublicKey alicPubKey = bobKeyFac.generatePublic(dhKeySpec);

Yes, I tried this as well. It won't throw any exception. It silently generate the public and secret key at server. but when I use server's public key at client to generate clients secret key, it ends up with having different secret key at both the end. The client secret key won't match with server's secret key.

 

Matt

Matt Caswell

unread,
Mar 19, 2013, 10:43:02 AM3/19/13
to
On 19 March 2013 14:18, azhar jodatti <azha...@gmail.com> wrote:
> On Tue, Mar 19, 2013 at 6:24 PM, Matt Caswell <fr...@baggins.org> wrote:
>> On 19 March 2013 12:22, azhar jodatti <azha...@gmail.com> wrote:
>> > PEM_write_bio_DHparams(out, temp);//this prints public key in
>> > base64
>> > (this is what i think :) )
>>
>> This is NOT a base64 representation of the public key. This is
>> printing out the parameters only (which does not include the public
>> key)
>>
>>
>> > X509EncodedKeySpec x509KeySpec = new
>> > X509EncodedKeySpec(clientPubKeyEnc);
>> > PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec);
>> > //
>> > this throws invalidKeySpecException : invalid key specification
>> >
>>
> What is the reason behind this? Why it won't work with X509EncodedKeySpec?
>
Because, as noted above the data you are trying to use is not what you
think it is. X509EncodedKeySpec expects an ASN.1 type of
"SubjectPublicKeyInfo", whereas you are providing an ASN.1 type of
DHparams.

>>
>> Instead of above, try something like this:
>>
>> BigInteger y = new
>>
>> BigInteger("4373485839237796166699589228729451887524557806298817546317652313209684941935291316056752499275686842785989445002203537603465313281932431907074220666705812428468899520395399424699433568818334649395647035588736697462362131440308900155995886437558059484184376957451229991382889256903754886307405909744230582829");
>> BigInteger p = new
>>
>> BigInteger("106824077746282794452228647025839229808074839339760371103063155402464842614962676228255294325459053774613506891207056818441720848774298482866918174271328357364028843638451324415691330056638482781344307395975948664971732094293996189467599104442989563027727348339786810653279203313302815966250977426622843204103");
>> BigInteger g = new BigInteger("5");
>> DHPublicKeySpec dhKeySpec = new DHPublicKeySpec(y, p, g);
>> PublicKey alicPubKey = bobKeyFac.generatePublic(dhKeySpec);
>>
>> Yes, I tried this as well. It won't throw any exception. It silently
>> generate the public and secret key at server. but when I use server's public
>> key at client to generate clients secret key, it ends up with having
>> different secret key at both the end. The client secret key won't match with
>> server's secret key.
>
It's not throwing an exception because it is a correctly formatted
public key as opposed to an incorrectly formatted one!

If you're not getting the same shared secret then we have to keep
looking for the next problem! Please can you show me the public key
that is generated from the Java, and how you are getting that into the
C.

azhar jodatti

unread,
Mar 20, 2013, 3:37:03 AM3/20/13
to
Public key : 51093028659631095152127547561210256954397603098232059666027122615973227382429027689439366800901894865255894412959274262339973658755087875326652519316408641291147210116350724179445600062190440655247730764834818870113073675659597350146096013520359779813721130161289129623836149432660886911252479058706300096609627440489763066216701057451976966454286830289446177423364030417328352835706375072921374017823594671329956408841840266423002727166432797742483425435318160265353606929428888687407883845458106878990927218108399715490559887862345042269910918508836619472642535350414785745034292564778165044378612630468960194913792482268072428278422412284738960598286710094132345557605518602478981231098046892613531283123151​

​   Secret key :
 121277045462377180924388960664136553887763629105491725197403931101683470015335768230267747273675733333930957394257354070595978655048643912250308681026844585744709027576900402249670187203160151084771397152790055765927595015924125212527820968758168922306979142896670732847778567823870168933256602812482617195330

These are the public and secret key generated at JAVA server.  I am passing public key to C.
below is the C code snippet which takes this key and generates secret key.

        printf("Enter server public key \n");
        unsigned char serverpublickey[1024];
        scanf("%s",serverpublickey);// reads the server public key
        BIGNUM *spubkey=BN_new();
        BIGNUM **ppubkey =&spubkey;
        BN_dec2bn(ppubkey,serverpublickey);//convert decimal key to BIGNUM
        printf("\nserver public key= \n");
        BN_print(out,*ppubkey);
        clientout=DH_compute_key(clientbuf,*ppubkey,client);


above DH_compute_key function returns -1 values and the error message it prints is "error:05066066:Diffie-Hellman routines:COMPUTE_KEY:invalid public key"

I am using below code to get this error
                unsigned long errorcode = ERR_get_error();
                ERR_error_string_n(errorcode, errbuf,sizeof errbuf);

 



Matt

Matt Caswell

unread,
Mar 20, 2013, 6:14:00 AM3/20/13
to
On 20 March 2013 07:37, azhar jodatti <azha...@gmail.com> wrote:
>> Public key :
>> 51093028659631095152127547561210256954397603098232059666027122615973227382429027689439366800901894865255894412959274262339973658755087875326652519316408641291147210116350724179445600062190440655247730764834818870113073675659597350146096013520359779813721130161289129623836149432660886911252479058706300096609627440489763066216701057451976966454286830289446177423364030417328352835706375072921374017823594671329956408841840266423002727166432797742483425435318160265353606929428888687407883845458106878990927218108399715490559887862345042269910918508836619472642535350414785745034292564778165044378612630468960194913792482268072428278422412284738960598286710094132345557605518602478981231098046892613531283123151
>>

This public key is too big. It is far larger than the value of p. How
are you extracting and printing it?

azhar jodatti

unread,
Mar 20, 2013, 7:25:37 AM3/20/13
to
On Wed, Mar 20, 2013 at 3:44 PM, Matt Caswell <fr...@baggins.org> wrote:
On 20 March 2013 07:37, azhar jodatti <azha...@gmail.com> wrote:
>> Public key :
>> 51093028659631095152127547561210256954397603098232059666027122615973227382429027689439366800901894865255894412959274262339973658755087875326652519316408641291147210116350724179445600062190440655247730764834818870113073675659597350146096013520359779813721130161289129623836149432660886911252479058706300096609627440489763066216701057451976966454286830289446177423364030417328352835706375072921374017823594671329956408841840266423002727166432797742483425435318160265353606929428888687407883845458106878990927218108399715490559887862345042269910918508836619472642535350414785745034292564778165044378612630468960194913792482268072428278422412284738960598286710094132345557605518602478981231098046892613531283123151
>>

This public key is too big. It is far larger than the value of p. How
are you extracting and printing it?


Java JCE generating this key. :( :(  Below is the code I am using to print this.

 
​      
byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();
​// this generated server's public key​
      
​       ​
 System.out.println("public key : "+ new BigInteger(bobPubKeyEnc));
​//prints public key in BigInteger (decimal)

​Even you can see the same steps in my previous mail threads where I pasted my complete JAVA and C code. Do you see any issue with this? or anything else ​







Matt Caswell

unread,
Mar 20, 2013, 7:42:49 AM3/20/13
to
On 20 March 2013 11:25, azhar jodatti <azha...@gmail.com> wrote:
> byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();

This is providing an encoded form of the public key, whereas your code
is expecting it as an integer. Use the following instead:

DHPublicKey dhpubkey = (DHPublicKey)(bobKpair.getPublic());
BigInteger bobPubKeyInt = dhpubkey.getY();

azhar jodatti

unread,
Mar 20, 2013, 3:21:16 PM3/20/13
to
On Wed, Mar 20, 2013 at 5:12 PM, Matt Caswell <fr...@baggins.org> wrote:
On 20 March 2013 11:25, azhar jodatti <azha...@gmail.com> wrote:
> byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();

This is providing an encoded form of the public key, whereas your code
is expecting it as an integer. Use the following instead:

DHPublicKey dhpubkey = (DHPublicKey)(bobKpair.getPublic());
BigInteger bobPubKeyInt = dhpubkey.getY();

Yes, Matt. This worked and it also generates same secret key at both the end :) :) :)
Thanks a lot. You been a great help to me.
One more query :).

After generating secret key :
byte[] bobSharedSecret = bobKeyAgree.generateSecret();//this generates secret key. Note : this key matches with C client secret key :)

I am doing below stuff in JAVA :
       SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
        DESKeySpec desSpec = new DESKeySpec(
bobSharedSecret);
        this.secretKey = skf.generateSecret(desSpec);

What is the equivalent of this in C?

this.secretKey is an object of javax.crypto.SecretKey which I am using for symmetric encryption like this
        byte[] utf8 = plaintext.getBytes("UTF8");
        Cipher c = Cipher.getInstance("DES");
        c.init(Cipher.ENCRYPT_MODE, this.secretKey);
        byte[] encryptedText =  c.doFinal(utf8);
        return new sun.misc.BASE64Encoder().encode(encryptedText);

and decryption like this
       Cipher c = Cipher.getInstance("DES");
        byte[] decryptBase64= new sun.misc.BASE64Decoder().decodeBuffer(incryptedData);
        c.init(Cipher.DECRYPT_MODE, this.secretKey);
        byte plaintext[] = c.doFinal(decryptBase64);
        return new String(plaintext,"UTF-8");


 
      





 

​  ​

Matt Caswell

unread,
Mar 20, 2013, 5:56:56 PM3/20/13
to
On 20 March 2013 19:21, azhar jodatti <azha...@gmail.com> wrote:

> One more query :).
>
> After generating secret key :
> byte[] bobSharedSecret = bobKeyAgree.generateSecret();//this generates
> secret key. Note : this key matches with C client secret key :)
>
> I am doing below stuff in JAVA :
> SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
> DESKeySpec desSpec = new DESKeySpec(bobSharedSecret);
> this.secretKey = skf.generateSecret(desSpec);
>
> What is the equivalent of this in C?

Well looking at the docs the DESKeySpec constructor just takes the
first 8 bytes of the byte array to form the key. The equivalent is to
just pass an unsigned char * pointing at the shared secret in the key
parameter in the call to EVP_EncryptInit_ex.

BUT - you should NOT use the shared secret directly like this. This
goes back to my point about implementing your own protocol - it is
easy to make a mistake like this. Protocols will typically pass the
shared secret through some message digest function (such as SHA2), and
use the output from that as the key. See section 2.1.2 of RFC2631 for
an example of this in practice. The problem is that the set of
possible DH shared secrets is not necessarily evenly distributed
within the keyspace. By using the shared secret directly you could
introduce biases into your encryption, which could in turn lead to a
security flaw. (As an aside another potential security problem with
DH is that it is susceptible to MITM attacks without some
authentication layer - another thing that protocols will typically
add)

For information on encryption with openssl see:
http://wiki.opensslfoundation.com/index.php/EVP
and in particular these pages linked from there:
http://wiki.opensslfoundation.com/index.php/EVP_Symmetric_Encryption_and_Decryption
http://wiki.opensslfoundation.com/index.php/EVP_Authenticated_Encryption_and_Decryption

Also see the manual pages:
http://www.openssl.org/docs/crypto/EVP_EncryptInit.html#

Message Digests are covered here:
http://wiki.opensslfoundation.com/index.php/EVP_Message_Digests
http://www.openssl.org/docs/crypto/EVP_DigestInit.html#

Dave Thompson

unread,
Mar 20, 2013, 8:21:29 PM3/20/13
to
>From: owner-ope...@openssl.org On Behalf Of azhar jodatti
>Sent: Wednesday, 20 March, 2013 15:21

>On Wed, Mar 20, 2013 at 5:12 PM, Matt Caswell <fr...@baggins.org> wrote:

> On 20 March 2013 11:25, azhar jodatti <azha...@gmail.com> wrote:
> > byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();

> This is providing an encoded form of the public key, whereas your
code
> is expecting it as an integer. Use the following instead:

> DHPublicKey dhpubkey = (DHPublicKey)(bobKpair.getPublic());
> BigInteger bobPubKeyInt = dhpubkey.getY();

To be exact, PublicKey.getEncoded() is returning the X509 encoding
of the parameters AND public value (y), which is why it looks huge.
Matt's correction correctly get y separately, as a number.

>One more query :).

>After generating secret key :
>byte[] bobSharedSecret = bobKeyAgree.generateSecret();
>//this generates secret key. Note : this key matches with C client secret
key :)

Actually that's the shared secret, as your name says.
Using the shared secret directly as a secret key is the naive
1970's version often shown in textbooks, but (most?) real
protocols and standards interpose a key derivation step.

Also this is good place to note that unauthenticated DH keyagreement
is insecure against an active attacker. Look for Ross Anderson's
paper "Mind your p's and q's".

>I am doing below stuff in JAVA :
> SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
> DESKeySpec desSpec = new DESKeySpec(bobSharedSecret);
> this.secretKey = skf.generateSecret(desSpec);

If you don't care about DES specifics (see below) you can use
SecretKeySpec with algorithm=DES and it implements interface Key
so you can pass it to Cipher.init without going through a factory.

>What is the equivalent of this in C?

*openssl* doesn't require magic data types like Java does,
but does require that a DES key be "scheduled" or "expanded"
before actual encrypt/decrypt. You can do this with the
encrypt/decrypt call, or (once) in advance like:

DES_key_schedule des_k;
DES_set_key[_checked/_unchecked] ((void*)secretkeyvalue, &des_k);

See man -3ssl des

(For other crypto libraries in C, answer is different.)

But note classic single DES is fallen for about 10 years.
Are you using a textbook from 1990 or something?

>this.secretKey is an object of javax.crypto.SecretKey which
>I am using for symmetric encryption like this
> byte[] utf8 = plaintext.getBytes("UTF8");
> Cipher c = Cipher.getInstance("DES");
> c.init(Cipher.ENCRYPT_MODE, this.secretKey);
> byte[] encryptedText = c.doFinal(utf8);
> return new sun.misc.BASE64Encoder().encode(encryptedText);

With the usual providers "DES" is really "DES/CBC/PKCS5Padding",
and it would be clearer to be explicit. I thought that CBC with
no IV specified uses a random IV, which you would need to transmit,
but on testing apparently it uses zeros, which in general is bad
but if you are using nonce DEKs it is tolerable.

Dave Thompson

unread,
Mar 25, 2013, 4:04:55 AM3/25/13
to
> From: owner-ope...@openssl.org On Behalf Of Dave Thompson
> Sent: Wednesday, 20 March, 2013 20:21
Correction: on more careful checking, it's DES/*ECB*/PKCS5Padding,
which for one block I looked at is the same as CBC IV=zeros (duh).
Sorry for the mislead.

azhar jodatti

unread,
Mar 25, 2013, 1:00:16 PM3/25/13
to
Thanks for the explanation and  help.. everything worked perfect. :) :)

Regards,
Azhar
0 new messages