Wednesday, 21 January 2015

How should API keys be generated (original post)?


It depends on how much you want to separate roles.
Basic system: your "signature" is a MAC. The "API key" is a secret value with is shared between the server and the user. Normal MAC algorithms like HMAC can use arbitrary sequences of bits as key, so a key is easily generated by using /dev/urandom (Linux, *BSD, MacOS X), calling CryptGenRandom()(Win32) or using java.security.SecureRandom (Java).
Enhanced system: your signature is a true digital signature. This makes sense if you want to separate the key generator (who can produce keys which will be accepted by the server) from the server itself (who validates the incoming signatures). Keys for signature algorithms are mathematical objects with a lot of internal structure, and each algorithm implies a specific key generation algorithm. Use a library which already implements the needed bits (e.g. OpenSSL).

Either way, there is more to it than just key generation and signatures. For instance, you probably want to avoid replay attacks: an ill-intentioned third party spies on the network, and records a valid request signed by a regular user. Later on, the attacker sends the request again, complete with its signature, so as to replicate the effect. To avoid replay attacks, you must add some sort of external protocols, and these things are hard to do (it is not hard to define a protocol; it is very hard to define a secure protocol). Therefore, the smart thing to do is reusing an existing, well-vetted protocol, which, in practice, meansSSL/TLS.
With SSL, the "basic system" is reduced to sending the API key in a header at the beginning of the conversation (that's exactly what happens with password authentication on HTTPS Web sites). The "enhanced system" is then "SSL with a client certificate
Basic system example in Java:

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.xml.bind.DatatypeConverter;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public class RandomAESKeyGen {
    public static String generate(final int keyLen) throws NoSuchAlgorithmException {

        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(keyLen);
        SecretKey secretKey = keyGen.generateKey();
        byte[] encoded = secretKey.getEncoded();
        return DatatypeConverter.printHexBinary(encoded).toLowerCase();
    }

    public static String generate2(final int keyLen) throws NoSuchAlgorithmException {

        SecureRandom random = new SecureRandom();
        byte bytes[] = new byte[keyLen/8];
        random.nextBytes(bytes);
        return DatatypeConverter.printHexBinary(bytes).toLowerCase();
    }

    public static void main(String[] args) {
        String key = null;
        for(int i=0; i< 5; ++i) {
            try {
                key = RandomAESKeyGen.generate(128);
            } catch (NoSuchAlgorithmException e) {
                System.out.println("Exception caught");
                e.printStackTrace();
            }
            System.out.println(key);
        }
        System.out.println("==================");

        for(int i=0; i< 5; ++i) {
            try {
                key = RandomAESKeyGen.generate2(256);
            } catch (NoSuchAlgorithmException e) {
                System.out.println("Exception caught");
                e.printStackTrace();
            }
            System.out.println(key);
        }
        System.out.println("==================");

        for(int i=0; i< 5; ++i) {
            try {
                key = RandomAESKeyGen.generate2(128);
            } catch (NoSuchAlgorithmException e) {
                System.out.println("Exception caught");
                e.printStackTrace();
            }
            System.out.println(key);
        }

        System.out.println("==================");
        for(int i=0; i< 5; ++i) {
            try {
                key = RandomAESKeyGen.generate2(256);
            } catch (NoSuchAlgorithmException e) {
                System.out.println("Exception caught");
                e.printStackTrace();
            }
            System.out.println(key);
        }
    }
}


Output:
477d79e9666e23b1d0cd21a369f792e6
ee14b8c42d28574b26a7698c1eb60bfd
31e62b393e8e832aca1f82cc15e894e8
dee41083d38c205bec59986bdfeb36d3
e3c832ca50d74bb952f76c667bd1a419
==================
d87096c6d5f936921f623e0a0c316630be5a73732d7dcfbca00ff621fba2043c
c977d946724b25bff2e9ab09d6437b0f58bb8ea32b7a126157e4b46625d57b8a
8a8c20cdb23b6cf297d70b2ad129cd1f28ad39dc40e2a636cd2b92d5da1f07bd
20989a0b6b66d0e640a276915ee0d8f314be644628aec1e5c31eed631e1202ff
ebd2ab5a685fc4a7959a4157a7e73bf4b31b00d738c226cbd0f0579f5250e67e
==================
282fab7899cb43d15eff9b6cf8dabfc9
5e3525a6c8bf7193bf1e8060bc5c369a
8e760cbb735160f3c29311cadb898283
79f843b204cc2c16d58cf041570734b0
5e05dbf8fe7955444eef3597f93a84e8
==================
bf238f136d2326c9e7e824bbb90632b7e12ed10974f987786f978a37c3eaf3ee
bf84fb6f726d4f568cd03ec74089b8044262861306c48dcee42b57e6eb252ab5
9fdb01f2fb3448f9e0d7b2566053a7e1bf087f67fab1555b1427ac4f204eed12
ea601341a215d1247b5a13854c97f64915dced3e2f457fa8f21a1d9710219db3
3b1fc36bf44230f907c045b8b4af166075224833f72325b4c2dba112791ad9af


Essentially generate() and generate2() are almost doing the same thing. From grepcode you can search KeyGenerator and get code

 protected void engineInit(int keysizeSecureRandom random) {
98
         if (((keysize % 8) != 0) ||
99
             (!AESCrypt.isKeySizeValid(keysize/8))) {
100
            throw new InvalidParameterException
101
                ("Wrong keysize: must be equal to 128, 192 or 256");
102
        }
103
        this. = keysize/8;
104
        this.engineInit(random);
105
    }

  protected SecretKey engineGenerateKey() {
113
        SecretKeySpec aesKey = null;
114

115
        if (this. == null) {
116
            this. = .;
117
        }
118

119
        byte[] keyBytes = new byte[];
120
        this..nextBytes(keyBytes);
121
        aesKey = new SecretKeySpec(keyBytes"AES");
122
        return aesKey;
123
    }

Or you can grab a JD - GUI and find <java_home>/jre/lib/ext/sunjce_proider.jar, open that up you can see very similar things:

  protected void engineInit(int paramInt, SecureRandom paramSecureRandom)
  {
    if ((paramInt % 8 != 0) || (!SunJCE_c.a(paramInt / 8))) {
      throw new InvalidParameterException("Wrong keysize: must be equal to 128, 192 or 256");
    }
    this.b = (paramInt / 8);
    engineInit(paramSecureRandom);
  }
 
  protected SecretKey engineGenerateKey()
  {
    SecretKeySpec localSecretKeySpec = null;
    if (this.a == null) {
      this.a = SunJCE.h;
    }
    byte[] arrayOfByte = new byte[this.b];
    this.a.nextBytes(arrayOfByte);
    localSecretKeySpec = new SecretKeySpec(arrayOfByte, "AES");
    return localSecretKeySpec;
  }
}





Soap security - WS-Security

WS-SecurityWeb服务安全)是一种提供在Web服务上应用安全的方法的网络传输协议。2004年4月19日,OASIS组织发布了WS-Security标准的1.0版本。 2006年2月17日,发布了1.1版本。
WS-Security是最初IBM微软VeriSignForum Systems开发的,现在协议由Oasis-Open下的一个委员会开发,官方名称为WSS。
协议包含了关于如何在Web服务消息上保证完整性和机密性的规约。WSS协议包括SAML(安全断言标记语言)、Kerberos和认证证书格式(如X.509)的使用的详细信息。
WS-Security描述了如何将签名和加密头加入SOAP消息。除此以外,还描述了如何在消息中加入安全令牌,包括二进制安全令牌,如X.509认证证书和Kerberos门票(ticket)。
WS-Security将安全特性放入一个SOAP消息的消息头中,在应用层处理。这样协议保证了端到端的安全。
WS主要是可利用HTTP,穿透防火墙。而Remoting可以利用TCP/IP,二进制传送提高效率。

Saturday, 27 December 2014

Total visitors since Jan 2012

World Visitor Map