PKE REST Auth using SHA-1 Hash - api

I'm designing my first RESTful API and am trying to figure out how I'm going to authenticate API calls. I've worked with the Gengo API (dev docs) in the past and had great luck with it, so admittedly, am basing a lot of my auth design on their algorithm described in that link.
To sum their process up, to create a valid/authenticated API call:
Register for an account with them and generate a public/private key set. Then for each API call:
Obtain the UNIX epoch timestamp that the call is being made at.
Calculate the SHA-1 hash of your timestamp "against" your private key.
Make sure that your public key, private key and the calculated hash (above) is present as 3 separate HTTP parameters with every single API call.
At first this was a little confusing to me, but I was able to get authentication working pretty quickly with their API. But I never fully understood why I had to generate this SHA-1 hash, and I had no clue what they were doing on the server-side to actually authenticate my API calls.
Now that I'm writing my own authenticated API, I need to understand these things. So I ask:
What purpose does the timestamp and its derived SHA-1 hash serve? Why is it less secure to just require users send me their public/private keys with each API call?
Is this pubkey + privkey + hashed_timestamp method that Gengo is using a standardized practice for API auth? If so, does it have a name/algorithm? Are there other, equally-secure competitors to it?
I'm confused by the whole HMAC/SHA-1 stuff (see the link above for concrete example). I always thought SHA-1 was a one-way function that turned a string into a unqiue, encoded strinig similar to what MD5 offers. But in that example (see link), it looks like it's passing SHA-1 and the string to some HMAC algorithm. What purpose does this HMAC serve and why does it require 3 arguments (SHA-1, the timestamp and the private key)?
Finally, what do I do with the 3 parameters (pub key, priv key, hashed timestamp) on the server-side to perform authentication? If I was designing a system that only used the pub/priv keys, then I would treat them like a username/password combo and would check the database to see if that combo existed or not. But the hashed timestamp is really throwing me off here.

What purpose does the timestamp and its derived SHA-1 hash serve? Why is it less secure to just require users send me their public/private keys with each API call?
To clear any misunderstanding you seem to have up front, the user should never send the private key over the network. The private key is to stay private. It is a secret shared between you and the user. Reread the Gengo link, you'll see that it is only used as a parameter to the HMAC function. It is up to the user to find a way to secure it, but your API does not need it to verify calls.
The timestamp serves two purposes. First it is a piece of data for which you will get both the plaintext and the HMAC. You will be recomputing the HMAC on your side with the private key of the user. If the HMAC checks, it means that not only the timestamp was not tampered with, but also that only someone knowing the private key could have sent it. It provides integrity and authenticity for that piece of data.
If it was a simple SHA1, a attacker could have intercepted the message, changed the timestamp, and recomputed the hash. By using a keyed hash, you ensure that the sender is who you think he is.
The second purpose for the timestamp is to prevent replay attacks. Even if using a keyed hash, the attacker could have captured an old request and send it again, possibly triggering unwanted actions. If your users hash the time and you test it and reject requests that are unreasonably old, you can prevent such replay attacks.
Is this pubkey + privkey + hashed_timestamp method that Gengo is using a standardized practice for API auth? If so, does it have a name/algorithm? Are there other, equally-secure competitors to it?
Again the privkey is not sent through the pipe. Using HMAC for API authentication is quite common. It is used for Amazon Web Services for example. When used in the Gengo way, the fact that there is seemingly a public/private key pair can be confusing, it is really still symmetric cryptography, and the private key is used as a shared secret.
However I think it is better to include more than just the timestamp in the data that is HMAC'ed. Otherwise an attacker could tamper with other parts of the request. The headers, the HTTP verb, and a hash of the content of the request should be included as well.
Another scheme is to use the private key on client side to sign (encrypt with the private key) a piece of data, so the server only needs to verify it with the public key of the client and needs not know the private key of the client. Embedding a time information is still needed to prevent replays. I do not know much about this scheme, it might be hard to reliably link clients with a given public key in the first place.
What purpose does this
HMAC serve and why does it require 3 arguments (SHA-1, the timestamp
and the private key)?
An HMAC is a keyed hash. Consider the simplest form of message authentication: hash(key + message). It was found that this was not secure (see length extension attack) and a nested structure fixes the vulnerability.
HMAC is a generic name of that structure: hash(k1 + hash(k2 + message)), where k1 and k2 are derived from the actual secret key. So when we do an HMAC we need to pass the name of the actual hash algorithm that will be used (here SHA-1), the message (here, the timestamp), and the secret key.
Finally, what do I do with the 3 parameters (pub key, priv key, hashed
timestamp) on the server-side to perform authentication? If I was
designing a system that only used the pub/priv keys, then I would
treat them like a username/password combo and would check the database
to see if that combo existed or not. But the hashed timestamp is
really throwing me off here.
Hopefully clearer by now. You use the public key as an identifier to retrieve the private key. You take the ts header and recompute the HMAC of it with the private key. If it matches with the hmac header sent, the request is authentic. You check the actual timestamp to see if it's not an old request replayed by some attacker. If all checks, the call can go through. I think it's better to embed all the important information in the HMAC, not just a timestamp though.

You need either public key cryptography or an HMAC, not both.
Let's come back to the timestamp later, and you're confusing authentication with integrity, which we'll also come back to later.
Authentication: in your case this is where the client proves knowledge of some secret to the server. Two common ways to do this are via public key cryptography and using an HMAC.
PKC: before using the service a public/private key pair is generated. The client has the private key; the server has the public key. Important: the private key never leaves the client. In particular, the server does not have access to the private key. To authenticate, the client encrypts some random value N (called a nonce), and sends N and its encrypted form to the server. The server uses the public key to decrypt the encrypted nonce and confirms that it equals the supplied nonce. This proves to the server that the client has the private key.
HMAC: client and server agree a shared secret K beforehand. To authenticate, the client creates a nonce N, computes HMAC(K, N), and sends N and HMAC(K, N) to the server. The server also computes HMAC(K, N) since it knows the shared secret and has received N from the client. If the computed and received HMAC(K, N) values are the same then the server knows that the client has the shared secret K.
The HMAC approach has one significant weakness compared with PKC: if the server is compromised then the attacked gains knowledge of K and can then use that to masquerade as the client.
If using PKC, ideally generate the keypair on the client and send the public key to the server. That way the server never has the private key.
However, unless the communication channel is confidential (e.g. uses SSL/TLS), both approaches have a problem: replay attacks. A passive observer can record the N+encrypted form, or N+HMAC(K,N) and replay them to the server. The server will then think that the observer is a valid client.
Two standard defences are:
Use a time-based nonce.
The server remembers previously-seen nonces, and rejects new requests that use a previously-seen nonce.
That's where the timestamp comes in, and is discussed in more detail here: Should I sign (with a public/private key) a form based authentication (no SSL)?
Integrity: we've proved to the server that we're a valid client, but we haven't provided any protection of the request itself. An attacker could modify our request in flight: we'd authenticate correctly but then execute the attacker's request rather than the client's original request.
To resolve this we need to protect the integrity of the request. We can do this with the same mechanism as above. Rather than just using a nonce (N) or nonce+timestamp, include the entire request in the data been encrypted or hashed. An important consideration here is that encrypted and hashing operate on bytes, not REST requests. You therefore need a reliable way to convert the REST request (i.e. HTTP method, URL, request parameters) into bytes. This is often called "canonicalisation": the client and server must both canonicalise the request in exactly the same way, so that they are encrypting/hashing the same bytes given the request.
This whole process is standardised in things like OAuth, e.g. https://dev.twitter.com/docs/auth/authorizing-request
To answer your specific questions:
The timestamp defends against replay attacks: passive observers can't reply a client's session. The SHA-1 hash is used as a component of the HMAC.
Yes, to a point. But I'd use a fully-fledged implementation of it rather than rolling your own, such as something OAuth-based.
An HMAC is a keyed hash: it's like a standard cryptographic hash (such as SHA-1, except that you also include a shared secret key in the hash. Simply concatenating the key to the data being hashed has cryptographic weaknesses that the HMAC construct avoids. (https://en.wikipedia.org/wiki/HMAC.)
If you're using PKC then you look up the client's public key on the server (based on some client ID, which ist not the client's private key), use that to decrypt the encrypted request, and verify that that request matches the received request. If you're using HMAC then you look up the client's shared secret, canonicalise the request, compute HMAC(K, R) and verify that it matches the received HMAC(K, R). In both cases you must also verify timestamps/nonces to protected against replays.
BUT: rule #1 of crypto: don't roll your own. Use an established mechanism, such as OAuth. You probably also want to use SSL/TLS, which would then also let you use client certificates as a third authentication option. If you used those then you could also rely on SSL/TLS to give you integrity and replay protection. However, implementing SSL/TLS certificate validation correctly seems to fox many developers...

Related

Encrypt with Public Key and decrypt with Private Key using elliptic-curve cryptography

everybody.
Is it possible to perform public key encryption flow for elliptic-curve cryptography?
https://en.wikipedia.org/wiki/Public-key_cryptography
I need to implement the following scenario:
Alice generates a message.
Alice encrypts it with Bob's public key.
Alice sends a message to Bob (via an insecure channel).
Bob gets the message.
Bob can decrypt this message only with his private key.
I can't find a proper method inside the tweetnacl lib (https://github.com/dchest/tweetnacl-js). Could somebody can direct me in the right direction?
Thank you in advance.
You should be looking for an ECIES implementation. Here is a random JavaScript library that seems to support it.
Elliptic Curves do not support a encryption primitive like RSA does. There is EC ElGamal but is not worth it due to the small key sizes and the amount of overhead of ElGamal.
To use curves with encryption you need to use hybrid encryption. ECIES is hybrid encryption: offline ECDH key agreement together with symmetric encryption performed using the derived secret key.
Note that ECIES is not well standardized. You may have to choose your own key derivation function, stream cipher or block cipher and mode of operation. For the key derivation method you could choose HKDF where available. AES in GCM mode seems a sane choice today for the cipher (the 12 byte IV may be set to zero or to a value derived from the "shared secret" as well). Libraries that support ECIES will probably have their own idea on what ECIES should look like, but beware of compatibility issues...
Isn't the encryption method in the documentation that you linked to for tweetnacl-js?
https://github.com/dchest/tweetnacl-js#naclboxmessage-nonce-theirpublickey-mysecretkey
nacl.box(message, nonce, theirPublicKey, mySecretKey)
Encrypts and authenticates message using peer's public key, our secret key, and the given nonce, which must be unique for each distinct message for a key pair.
Returns an encrypted and authenticated message, which is nacl.box.overheadLength longer than the original message.
You would use the recipient's public key as the third argument to the above function. You would use your own private key as the fourth argument. The library takes care of message integrity by creating a signature of the encrypted message, signed by your private key.
I will suggest you go to an easy library that makes the work for you, I specially like the python ecdsa module (https://github.com/warner/python-ecdsa), is easy and not complicated. Also read about how EC works will help you in make your decision.

Asymmetric cryptography and JWT

I'm trying to understand how JWT is implemented in a codebase that I'm reviewing. I read this and this
However, it seems in this codebase, the client has the private AND public key... It has the public key of the server and its own private key (I assume the server has the corresponding private key). Why is this necessary? Shouldn't the client only need the public key and the server only needs the private key? If the client is encrypting a message, can't it use the public key to encrypt it and the server just needs the private key to decrypt it? Conversely, can't it decrypt encrypted messages from the server with its public key? Why would the client need two sets of public and private keys?
From the reading:
To create a digital signature, signing software (such as an email program) creates a one-way hash of the electronic data to be signed. The user's private key is then used to encrypt the hash, returning a value that is unique to the hashed data. The encrypted hash, along with other information such as the hashing algorithm, forms the digital signature. Any change in the data, even to a single bit, results in a different hash value. This attribute enables others to validate the integrity of the data by using the signer's public key to decrypt the hash. If the decrypted hash matches a second computed hash of the same data, it proves that the data hasn't changed since it was signed.
What is the differnce between the hashed data and encrypted data? Why do you need to hash it first? Are hashed data encrypted?
Where doe that secon computed hash come from? If the decryptor is attempting to apply the public key to the encrypted data... how does it know it succeeded? What does it compare it to? Where does that comparison hash come from?
JWT is signed (not encrypted) with the private key of the sender. jWT content can be encrypted optionally using JWE.
A symmetric key is used to sign and verify. With an asymmetric key pair, the message is signed with private key and verified with the public.
A digital signature protects the message against alterations and identify the sender. An asymmetric key allows the receiver to verify the signature using sender's public key without compromise the private key
JWT signing can be used both in client or server side depending on the purpose. For example, in an authentication flow
client side: API requests, where the server validates signature with public key uploaded during registration
server side: issue tokens to final users after presenting credentials
Internally, a digital signature involves several cryptographic operations, digest the message, encrypt the hash and add the algorithm identifier. But you do not have to worry about this because all programming languages ​​support it
I tried to explain JWT&digital signatures in a general way instead of answering your specific questions. I probably have left some. Please comment

JAX-RS security and Authentication

I am developing REST webService , and some of my client will use my webservices , so for identify the genuine client , I have decided to give them a unique Application Token to each genuine client . The client will encode this Token and they will put this Token in Request header and I have configure a REST filter in my REST webservices to verify Token . I dont want to use https . My problem is that any one can take that Token from my client site and can consume my REST webservices . How I can stop this ?
Since you dont want to use https, I assume confidentiality is not an issue here, and that you only want to authorize requests based on who is making them. Instead of passing a plain token, which could get stolen, you should ask your clients to sign their requests. You have a good explanation over here:
Implementing HMAC authentication for REST API with Spring Security
Using HMAC to authenticate Web service requests
websec.io - API Authentication
In short, and taken from Implementing HMAC authentication for REST API with Spring Security:
Client and server share a secret access key and a public access key.
Client create a request that contains three fundamental elements: the public key header (in plain text), a date header, a signature string calculated hashing some data of the request with the secret access key. This hash usually contains the http method, the uri path, the value of the date header (for reply attacks), all the content of the request (for POST and PUT methods) and the content type.
Client send the request to the server.
Server read the public key header and use it to retrieve the corresponding private access key.
Server use the private access key to calculate the signature in the same way as the client did.
Server check if the just-calculated signature matches with the one sent by the client.
(OPTIONAL) To prevent reply attacks, server checks that the value in the date header is within an acceptable limit (usually between 5 and 15 minutes to account clock discrepancy). The value cannot be manipulated by malicious attacker because the date it's used as part of the signature. If someone change the date header, the server will calculated a different signature of that calculated by the client, so step 6 will fail.
This logic can be implemented using any programming language. Following is a pseudo-code signature example in java:
//clientId is the public client identifier
//secretKey is the key shared between server and client
//requestContent is a string representation of the HTTP request (HTTP verb, body, etc.
//init signing key and mac
SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
//sign the request content
byte[] rawHmac = mac.doFinal(requestContent.getBytes());
//encode to base64
String result = base64(rawHmac);
//store in header
request.setHeader("Authorization", "MyAPI " + clientId + ":" + result);
On the server side, when you receive that request, you extract the clientId and signature from the header, retrieve the secret key corresponding to the clientId received, re-compute the signature (exactly as above) and compare the results. It it matches client is authorized, if not you return an HTTP 403 (or whatever error you want).
There is then no more "secrets" to steal for a potential man in the middle, BUT there are still keys that need to be securely stored on both the clients and the server. Leaking those keys will compromise the whole system.
As token cannot be securely transmitted on HTTP layer one can easily get this token. You can ask genuine client to encrypt this token by combining some logic having timestamp so that every time token is encrypted using some different algorithm and on server side you should follow similar algorithm to decrypt it. This way even if someone get hold of token that can't be reused. One way is to club this encryption logic with Google Authenticator. (http://www.techrepublic.com/blog/google-in-the-enterprise/use-google-authenticator-to-securely-login-to-non-google-sites/)
Use the checksum to secure the messages as below
MD5 or SHA1 checksum should be used to validate a password without passing the actual password.
The server sends a random string to the client.
The client appends his password to the random string, and returns an MD5/SHA1 sum of the result to the server.
On the server, do the same and compare the MD5/SHA1 sums.
If both MD5/SHA1 are identicals then the password is good and message is not changed.

How to get Authorization Token

I secured my Web Api using Token Based authentication. All works well, but for now before making an api call, I request for a token by making separate api call which will return me the token for making further request. What I am wondering is there any possible way that I can generate token on client side which will be decrypted on the server?
OR
What you think, I am on the right track?
Here is my jQuery Code
$.when($.get("/api/service/GetToken"))
.done(function (token) {
doAjaxCall("GET", "/api/service/GetAllJobsStatusCount/1/admin", "{}", "json", token, function (data) {
console.log(data);
});
});
Here is my method which will return me token
[Api.HttpGet]
public string GetToken()
{
var authorizeToken = "apikey";
return Rsa.Encrypt(authorizeToken);
}
Please suggest
A single token only works for authentication if an encrypted connection (HTTPS) is used - otherwise, MITMs can read the token and steal the identity. If everything is done using secure connections, it doesn't matter who calculates the token, as long as it is exchanged before any authentications, so both partners know it beforehand - otherwise there would be no way to know if it's valid or not. Note however that the token can always only prove that the client is the one that the token was given to (or recevied from) in the first place, you still don't know anything else (for example if the other person was who he claimed when te exchange was made).
If not using secure connections, I'd suggest using public-key encryption. If not encrypting the whole request, calculate a signature and sign it with the private key clientside, verify it server-side. In this case, the client MUST calculate the private and the public key and hand the public key over to the server, as the server should never know the client's private key (and it shouldn't ever be sent over a unencrypted connection either, after all that'S the whole point of using PKI).
For another approach (that is widely used, but not extraordinary secure), see OAuth.
[Edit]: Addition based on comment:
To verify a client, every request that accesses valuable data has to be authenticated. That means: the client needs to send something that is able to prove that it is who it claims to be along with EVERY request (as HTTP is a stateless protocol).
The usual way is to exchange some secret once, that is valid for either a limited time or forever, and only known to the client and the servet. That way, the server can verify idientities by checking if the client sent the token it was given. Expiring tokens after improves security, but when a client requests a knew one, there is no way to tell if it is the same client that used the old one (unless the request is validated by the old token and that one is still valid).
If ther client calculates the token, that deosn'T change anything - it sends it once and tells the server who it is, then every request that carries the same token does most likely come from the same client. There is only one additional thing the server has to do here: If two clients calculate the same token, the server has to reject the token from the second client and request another one. Otherwise, clients cannot be distinguished anymore.

Public and private API keys

I'm developing an API system which requires this type of authentication. The user will send an HTTP request with its id, the data, and a hash (the data hashed with the private key) and then in the server I check if the hash matches with the same procees here.
Is it like the implementation must be?
And I'm going to use as public key the id of the client but what is the best method to generate the private key, sha256 of the id, of a randon number?
This is not Private/Public-key cryptography. In such a system, the client would encrypt the whole data and you would then decrypt it using your private key. You would never give your private key to the client.
What you are doing is request signature. You give a "secret" (what you are calling "private key"), then they use this to generate a hash. You can then check the hash on your server since you also know the secret.
There would not be a public key in this kind of system. You normally identify the client using a session key or token, so the client needs to authenticate first (which means you need some authentication method). Essentially, what you are trying to implement is OAuth. Perhaps have a look at the library and see if you can use it directly - http://oauth.net/documentation/getting-started/
checking out what amazon s3 is doing for the authentication might be a good start
basically they are doing the same thing as you proposed, and they use RFC 2104HMAC-SHA1 for the hashing. The implementation depends on your choice of languages.