/** * blockmix_salsa8(B, Y, r): * Compute B = BlockMix_{salsa20/8, r}(B). The input B must be 128r bytes in * length; the temporary space Y must also be the same size. */ static void blockmix_salsa8(uint32_t * B, uint32_t * Y, size_t r) { uint32_t X[16]; size_t i; /* 1: X <-- B_{2r - 1} */ blkcpy(X, &B[(2 * r - 1) * 16], 16); /* 2: for i = 0 to 2r - 1 do */ for (i = 0; i < 2 * r; i++) { /* 3: X <-- H(X \xor B_i) */ blkxor(X, &B[i * 16], 16); salsa20(X, 8); /* 4: Y_i <-- X */ blkcpy(&Y[i * 16], X, 16); } /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ for (i = 0; i < r; i++) blkcpy(&B[i * 16], &Y[(i * 2) * 16], 16); for (i = 0; i < r; i++) blkcpy(&B[(i + r) * 16], &Y[(i * 2 + 1) * 16], 16); }
// Salsa expansion of key. Expansion of key depends from key length static void salsa_expand_key(struct salsa_context *ctx) { int i, j; uint8_t *expand; // Unique constant for key length 16 byte uint8_t key_expand_16 [] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '1', '6', '-', 'b', 'y', 't', 'e', ' ', 'k' }; // Unique constant for key length 32 byte uint8_t key_expand_32 [] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', '2', '-', 'b', 'y', 't', 'e', ' ', 'k' }; switch(ctx->keylen) { case SALSA16 : expand = (uint8_t *)key_expand_16; break; case SALSA32 : expand = (uint8_t *)key_expand_32; break; } j = 0; for(i = 0; i < 64; i+=20) { ctx->seq[i] = expand[j++]; ctx->seq[i + 1] = expand[j++]; ctx->seq[i + 2] = expand[j++]; ctx->seq[i + 3] = expand[j++]; } for(i = 0; i < 16; i++) { ctx->seq[4 + i] = ctx->key[i]; ctx->seq[24 + i] = ctx->nonce[i]; ctx->seq[44 + i] = ctx->key[ctx->keylen - 16 + i]; } // Salsa hash function salsa20(ctx->seq); }
/* * Set the Salsa IV */ void Salsa20::set_iv(const uint8_t iv[], size_t length) { if(!valid_iv_length(length)) throw Invalid_IV_Length(name(), length); if(length == 0) { // Salsa20 null IV m_state[6] = 0; m_state[7] = 0; } else if(length == 8) { // Salsa20 m_state[6] = load_le<uint32_t>(iv, 0); m_state[7] = load_le<uint32_t>(iv, 1); } else { // XSalsa20 m_state[6] = load_le<uint32_t>(iv, 0); m_state[7] = load_le<uint32_t>(iv, 1); m_state[8] = load_le<uint32_t>(iv, 2); m_state[9] = load_le<uint32_t>(iv, 3); secure_vector<uint32_t> hsalsa(8); hsalsa20(hsalsa.data(), m_state.data()); m_state[ 1] = hsalsa[0]; m_state[ 2] = hsalsa[1]; m_state[ 3] = hsalsa[2]; m_state[ 4] = hsalsa[3]; m_state[ 6] = load_le<uint32_t>(iv, 4); m_state[ 7] = load_le<uint32_t>(iv, 5); m_state[11] = hsalsa[4]; m_state[12] = hsalsa[5]; m_state[13] = hsalsa[6]; m_state[14] = hsalsa[7]; } m_state[8] = 0; m_state[9] = 0; salsa20(m_buffer.data(), m_state.data()); ++m_state[8]; m_state[9] += (m_state[8] == 0); m_position = 0; }
/* * Combine cipher stream with message */ void Salsa20::cipher(const uint8_t in[], uint8_t out[], size_t length) { while(length >= m_buffer.size() - m_position) { xor_buf(out, in, &m_buffer[m_position], m_buffer.size() - m_position); length -= (m_buffer.size() - m_position); in += (m_buffer.size() - m_position); out += (m_buffer.size() - m_position); salsa20(m_buffer.data(), m_state.data()); ++m_state[8]; m_state[9] += (m_state[8] == 0); m_position = 0; } xor_buf(out, in, &m_buffer[m_position], length); m_position += length; }
int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); const char key[] = { 0x00, 0x09, 0x70, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x3f }; const char in[] = { 0x00, 0x11, 0x11, 0x11, 0x13, 0x12, 0x12, 0x12, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0xdb, 0xdc, 0xdd, 0xde, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x12, 0x12, 0x12, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x12, 0x12, 0x12, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, }; const char iv[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x23, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfc }; QByteArray _key(key, 32); QByteArray _in(in, 28); QByteArray _iv(iv, 16); AES aes(_key, _iv); RC4 rc4(_key, _iv); Salsa20 salsa20(_key, _iv); qDebug() << "\nAES encryptor - CFB \n"; QByteArray encode_in = aes.update_CFB(_in, true); qDebug() << "AES encode " << encode_in << " :size: " << encode_in.size(); QByteArray decode_in = aes.update_CFB(encode_in, false); qDebug() << "RC4 decode " << decode_in << " :size: " << decode_in.size(); qDebug() << "\nRC4 encryptor \n"; QByteArray _encode_in = rc4.update(_in); qDebug() << "RC4 encode " << _encode_in << " :size: " << _encode_in.size(); QByteArray _decode_in = rc4.update(_encode_in); qDebug() << "RC4 decode " << _decode_in << " :size: " << _decode_in.size(); qDebug() << "\nSalsa20 encryptor \n"; QByteArray __encode_in = salsa20.update(_in); qDebug() << "RC4 encode " << __encode_in << " :size: " << __encode_in.size(); QByteArray __decode_in = salsa20.update(__encode_in); qDebug() << "RC4 decode " << __decode_in << " :size: " << __decode_in.size(); return a.exec(); }