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
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
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?
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.
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? :) :)
>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.
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
However, you are correct that the DH computation does not use q, although I do notknow whether JCE requires it to be specified (not having used JCE).
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.Mattkpg.initialize(new DHParameterSpec(/* p value passed from C */, /* g
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH");
value passed from C */));
keyPair = kpg.generateKeyPair();
Matt
On 19 March 2013 12:22, azhar jodatti <azha...@gmail.com> wrote:This is NOT a base64 representation of the public key. This is
> PEM_write_bio_DHparams(out, temp);//this prints public key in base64
> (this is what i think :) )
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);
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
Public key : 51093028659631095152127547561210256954397603098232059666027122615973227382429027689439366800901894865255894412959274262339973658755087875326652519316408641291147210116350724179445600062190440655247730764834818870113073675659597350146096013520359779813721130161289129623836149432660886911252479058706300096609627440489763066216701057451976966454286830289446177423364030417328352835706375072921374017823594671329956408841840266423002727166432797742483425435318160265353606929428888687407883845458106878990927218108399715490559887862345042269910918508836619472642535350414785745034292564778165044378612630468960194913792482268072428278422412284738960598286710094132345557605518602478981231098046892613531283123151
Matt
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?
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();