int crypto_stream( unsigned char *c,unsigned long long clen, const unsigned char *n, const unsigned char *k ) { return crypto_stream_xor(c,0,clen,n,k); }
int crypto_stream( unsigned char *out, unsigned long long outlen, const unsigned char *n, const unsigned char *k ) { memset(out,0,outlen); return crypto_stream_xor(out,out,outlen,n,k); }
int crypto_stream( unsigned char *c,crypto_uint16 clen, const unsigned char *n, const unsigned char *k ) { crypto_uint16 i; for(i=0;i<clen;i++) c[i] = 0; return crypto_stream_xor(c,c,clen,n,k); }
int crypto_stream( unsigned char *c, unsigned long long l, const unsigned char *n, const unsigned char *k ) { long long i; for (i = 0; i < l; ++i) c[i] = 0; return crypto_stream_xor(c, c, l, n, k); }
QString ClientConfiguration::toBackup(QString const& password) const { QByteArray encryptionKey(BACKUP_ENCRYPTION_KEY_BYTES, 0x00); // Generate a Salt QByteArray salt(BACKUP_SALT_BYTES, 0x00); randombytes_buf(salt.data(), BACKUP_SALT_BYTES); // Convert the password into bytes QByteArray password8Bit = password.toUtf8(); // Generate the encryption key for the Backup from the Salt and the Password PKCS5_PBKDF2_HMAC(reinterpret_cast<unsigned char*>(password8Bit.data()), password8Bit.size(), reinterpret_cast<unsigned char*>(salt.data()), BACKUP_SALT_BYTES, BACKUP_KEY_PBKDF_ITERATIONS, BACKUP_ENCRYPTION_KEY_BYTES, reinterpret_cast<unsigned char*>(encryptionKey.data())); QByteArray nonceBytes(crypto_stream_NONCEBYTES, 0x00); // The backup content QByteArray clientId(IdentityHelper::uint64ToIdentityString(getClientIdentity().getContactId()).toLatin1()); if (clientId.size() != BACKUP_IDENTITY_BYTES) { throw InternalErrorException() << QString("Could not build backup - invalid client identity length (%1 vs. %2 Bytes).").arg(clientId.size()).arg(BACKUP_IDENTITY_BYTES).toStdString(); } QByteArray clientSecKey(getClientLongTermKeyPair().getPrivateKey()); if (clientSecKey.size() != PROTO_KEY_LENGTH_BYTES) { throw InternalErrorException() << QString("Could not build backup - invalid client secret key length (%1 vs. %2 Bytes).").arg(clientSecKey.size()).arg(PROTO_KEY_LENGTH_BYTES).toStdString(); } QByteArray backup(salt); backup.append(clientId); backup.append(clientSecKey); // Compute Hash QByteArray controlHash(crypto_hash_sha256_BYTES, 0x00); crypto_hash_sha256(reinterpret_cast<unsigned char*>(controlHash.data()), reinterpret_cast<unsigned char*>(backup.data() + BACKUP_SALT_BYTES), BACKUP_IDENTITY_BYTES + PROTO_KEY_LENGTH_BYTES); backup.append(controlHash.left(BACKUP_HASH_BYTES)); if (backup.size() != (BACKUP_SALT_BYTES + BACKUP_IDENTITY_BYTES + PROTO_KEY_LENGTH_BYTES + BACKUP_HASH_BYTES)) { throw InternalErrorException() << QString("Could not build backup - invalid packet length (%1 vs. %2 Bytes).").arg(clientSecKey.size()).arg(BACKUP_SALT_BYTES + BACKUP_IDENTITY_BYTES + PROTO_KEY_LENGTH_BYTES + BACKUP_HASH_BYTES).toStdString(); } // The Backup is build from SALT + IDENTITY + KEY + HASH crypto_stream_xor(reinterpret_cast<unsigned char*>(backup.data() + BACKUP_SALT_BYTES), reinterpret_cast<unsigned char*>(backup.data() + BACKUP_SALT_BYTES), BACKUP_IDENTITY_BYTES + PROTO_KEY_LENGTH_BYTES + BACKUP_HASH_BYTES, reinterpret_cast<unsigned char*>(nonceBytes.data()), reinterpret_cast<unsigned char*>(encryptionKey.data())); // Encode in Base32 return Base32::encodeBase32Sequence(backup); }
i64 packet_encrypt(u8 *output, u8* key, u8 *data, i64 size) { u8 nonce[NONCE_BYTES]; if (!output || !key || !data || size < IPV4_AND_UDP_HEADER_SIZE) { return -1; } randombytes(nonce, NONCE_BYTES); crypto_stream_xor(output + NONCE_BYTES + IPV4_AND_UDP_HEADER_SIZE, data + IPV4_AND_UDP_HEADER_SIZE, size - IPV4_AND_UDP_HEADER_SIZE, nonce, key); memcpy(output, data, IPV4_AND_UDP_HEADER_SIZE); memcpy(output + IPV4_AND_UDP_HEADER_SIZE, nonce, NONCE_BYTES); return size + NONCE_BYTES; }
i64 packet_decrypt(u8 *output, u8* key, u8 *data, i64 size) { u8 nonce[NONCE_BYTES]; if (!output || !key || !data || size < (IPV4_AND_UDP_HEADER_SIZE + NONCE_BYTES)) { return -1; } memcpy(nonce, data + IPV4_AND_UDP_HEADER_SIZE, NONCE_BYTES); crypto_stream_xor(output + IPV4_AND_UDP_HEADER_SIZE, data + NONCE_BYTES + IPV4_AND_UDP_HEADER_SIZE, size - IPV4_AND_UDP_HEADER_SIZE - NONCE_BYTES, nonce, key); memcpy(output, data, IPV4_AND_UDP_HEADER_SIZE); return size - NONCE_BYTES; }
ClientConfiguration::BackupData ClientConfiguration::fromBackup(QString const& backup, QString const& password) { QByteArray decodedBase32 = Base32::decodeBase32Sequence(backup); if (decodedBase32.size() != BACKUP_DECODED_BYTES) { throw IllegalArgumentException() << "Invalid Backup: Size of decoded Backup String is incorrect (" << decodedBase32.size() << " Bytes instead of " << BACKUP_DECODED_BYTES << " Bytes)."; } unsigned char encryptionKey[BACKUP_ENCRYPTION_KEY_BYTES]; sodium_memzero(encryptionKey, BACKUP_ENCRYPTION_KEY_BYTES); // The pointer to the base32-decoded Backup unsigned char* decodedBase32Ptr = reinterpret_cast<unsigned char*>(decodedBase32.data()); // The Salt used in the PBKDF2 Key Derivation process is embedded in the first 8 bytes of the Backup. QByteArray password8Bit = password.toUtf8(); PKCS5_PBKDF2_HMAC(reinterpret_cast<unsigned char*>(password8Bit.data()), password8Bit.size(), decodedBase32Ptr, BACKUP_SALT_BYTES, BACKUP_KEY_PBKDF_ITERATIONS, BACKUP_ENCRYPTION_KEY_BYTES, encryptionKey); unsigned char nonceBytes[crypto_stream_NONCEBYTES]; sodium_memzero(nonceBytes, crypto_stream_NONCEBYTES); crypto_stream_xor(&decodedBase32Ptr[BACKUP_SALT_BYTES], &decodedBase32Ptr[BACKUP_SALT_BYTES], BACKUP_IDENTITY_BYTES + PROTO_KEY_LENGTH_BYTES + BACKUP_HASH_BYTES, nonceBytes, encryptionKey); // The last two bytes of the Backup contain the truncated SHA-256 Hash over the identity and its Private Key. unsigned char controlHash[crypto_hash_sha256_BYTES]; sodium_memzero(controlHash, crypto_hash_sha256_BYTES); crypto_hash_sha256(controlHash, &(decodedBase32Ptr[BACKUP_SALT_BYTES]), BACKUP_IDENTITY_BYTES + PROTO_KEY_LENGTH_BYTES); if (sodium_memcmp(&(decodedBase32Ptr[BACKUP_SALT_BYTES + BACKUP_IDENTITY_BYTES + PROTO_KEY_LENGTH_BYTES]), controlHash, BACKUP_HASH_BYTES) != 0) { throw IllegalArgumentException() << "Decryption of Backup failed: Invalid Control Hash (" << controlHash[0] << controlHash[1] << " vs. " << decodedBase32Ptr[BACKUP_SALT_BYTES + BACKUP_IDENTITY_BYTES + PROTO_KEY_LENGTH_BYTES] << decodedBase32Ptr[BACKUP_SALT_BYTES + BACKUP_IDENTITY_BYTES + PROTO_KEY_LENGTH_BYTES + 1] << ")."; } unsigned char derivedPublicKey[PROTO_KEY_LENGTH_BYTES]; crypto_scalarmult_base(derivedPublicKey, &decodedBase32Ptr[BACKUP_SALT_BYTES + BACKUP_IDENTITY_BYTES]); KeyPair kp = KeyPair::fromArrays(derivedPublicKey, &decodedBase32Ptr[BACKUP_SALT_BYTES + BACKUP_IDENTITY_BYTES]); QString identityString(QByteArray(reinterpret_cast<char*>(&decodedBase32Ptr[BACKUP_SALT_BYTES]), BACKUP_IDENTITY_BYTES)); if (!isValidIdentity(identityString)) { throw IllegalArgumentException() << "Invalid ClientConfiguration: Decryption of Backup failed: Not a valid Identity."; } return BackupData(ContactId(identityString.toUtf8()), kp); }
static nif_term_t salt_stream_xor(nif_heap_t *hp, int argc, const nif_term_t argv[]) { /* salt_stream_xor(In_text, Nonce, Secret_key) -> Out_text. */ nif_bin_t it; nif_bin_t nc; nif_bin_t sk; nif_bin_t ot; if (argc != 3) return (BADARG); /* Unpack arguments ensuring they're suitably typed. */ if (! enif_inspect_binary(hp, argv[0], &it)) return (BADARG); if (! enif_inspect_binary(hp, argv[1], &nc)) return (BADARG); if (! enif_inspect_binary(hp, argv[2], &sk)) return (BADARG); /* Check constraints on size. */ if (it.size < 1 || it.size > SALT_MAX_MESSAGE_SIZE) return (BADARG); if (nc.size != crypto_stream_NONCEBYTES) return (BADARG); if (sk.size != crypto_stream_KEYBYTES) return (BADARG); /* Allocate space for output byte stream. NB: Passing ENOMEM as BADARG. */ if (! enif_alloc_binary(it.size, &ot)) return (BADARG); (void)crypto_stream_xor(ot.data, it.data, it.size, nc.data, sk.data); return (enif_make_binary(hp, &ot)); }
bool unit_test_crypto_stream(){ // Global length uint64_t len = HACL_UNIT_TESTS_SIZE * sizeof(uint8_t); // Scratch buffers uint8_t hacl_cipher[HACL_UNIT_TESTS_SIZE], expected_cipher[HACL_UNIT_TESTS_SIZE]; // Shared key uint8_t key[32], nonce[24]; // Random plaintext uint8_t *plaintext = malloc(HACL_UNIT_TESTS_SIZE * sizeof (uint8_t)); READ_RANDOM_BYTES(len, plaintext); // Test 1 int a; bool pass = true; for (int i = 0; i < 1024; i++){ tweet_crypto_stream(expected_cipher, i, nonce, key); crypto_stream(hacl_cipher, i, nonce, key); a = memcmp(hacl_cipher, expected_cipher, i * sizeof(uint8_t)); if (a != 0){ pass = false; printf("SECRETBOX failed on input of size %d\n.", i); break; } } if (!pass) return pass; // Test 2 tweet_crypto_stream_xor(expected_cipher, plaintext, HACL_UNIT_TESTS_SIZE, nonce, key); crypto_stream_xor(hacl_cipher, plaintext, HACL_UNIT_TESTS_SIZE, nonce, key); a = memcmp(hacl_cipher, expected_cipher, HACL_UNIT_TESTS_SIZE * sizeof(uint8_t)); if (a != 0){ pass = false; printf("SECRETBOX failed on input of size %d\n.", HACL_UNIT_TESTS_SIZE); } free(plaintext); return pass; }
const char *checksum_compute(void) { long long i; long long j; for (i = 0;i < CHECKSUM_BYTES;++i) { long long mlen = i; long long clen = i; long long slen = i; long long klen = crypto_stream_KEYBYTES; long long nlen = crypto_stream_NONCEBYTES; for (j = -16;j < 0;++j) m[j] = rand(); for (j = -16;j < 0;++j) c[j] = rand(); for (j = -16;j < 0;++j) s[j] = rand(); for (j = -16;j < 0;++j) n[j] = rand(); for (j = -16;j < 0;++j) k[j] = rand(); for (j = mlen;j < mlen + 16;++j) m[j] = rand(); for (j = clen;j < clen + 16;++j) c[j] = rand(); for (j = slen;j < slen + 16;++j) s[j] = rand(); for (j = nlen;j < nlen + 16;++j) n[j] = rand(); for (j = klen;j < klen + 16;++j) k[j] = rand(); for (j = -16;j < mlen + 16;++j) m2[j] = m[j]; for (j = -16;j < clen + 16;++j) c2[j] = c[j]; for (j = -16;j < slen + 16;++j) s2[j] = s[j]; for (j = -16;j < nlen + 16;++j) n2[j] = n[j]; for (j = -16;j < klen + 16;++j) k2[j] = k[j]; crypto_stream_xor(c,m,mlen,n,k); for (j = -16;j < mlen + 16;++j) if (m[j] != m2[j]) return "crypto_stream_xor overwrites m"; for (j = -16;j < slen + 16;++j) if (s[j] != s2[j]) return "crypto_stream_xor overwrites s"; for (j = -16;j < nlen + 16;++j) if (n[j] != n2[j]) return "crypto_stream_xor overwrites n"; for (j = -16;j < klen + 16;++j) if (k[j] != k2[j]) return "crypto_stream_xor overwrites k"; for (j = -16;j < 0;++j) if (c[j] != c2[j]) return "crypto_stream_xor writes before output"; for (j = clen;j < clen + 16;++j) if (c[j] != c2[j]) return "crypto_stream_xor writes after output"; for (j = -16;j < clen + 16;++j) c2[j] = c[j]; crypto_stream(s,slen,n,k); for (j = -16;j < mlen + 16;++j) if (m[j] != m2[j]) return "crypto_stream overwrites m"; for (j = -16;j < clen + 16;++j) if (c[j] != c2[j]) return "crypto_stream overwrites c"; for (j = -16;j < nlen + 16;++j) if (n[j] != n2[j]) return "crypto_stream overwrites n"; for (j = -16;j < klen + 16;++j) if (k[j] != k2[j]) return "crypto_stream overwrites k"; for (j = -16;j < 0;++j) if (s[j] != s2[j]) return "crypto_stream writes before output"; for (j = slen;j < slen + 16;++j) if (s[j] != s2[j]) return "crypto_stream writes after output"; for (j = 0;j < mlen;++j) if ((s[j] ^ m[j]) != c[j]) return "crypto_stream_xor does not match crypto_stream"; for (j = 0;j < clen;++j) k[j % klen] ^= c[j]; crypto_stream_xor(m,c,clen,n,k); crypto_stream(s,slen,n,k); for (j = 0;j < mlen;++j) if ((s[j] ^ m[j]) != c[j]) return "crypto_stream_xor does not match crypto_stream"; for (j = 0;j < mlen;++j) n[j % nlen] ^= m[j]; m[mlen] = 0; } sodium_bin2hex(checksum, sizeof checksum, k, crypto_stream_KEYBYTES); return 0; }
void doit(void) { crypto_stream_xor(c,m,TUNE_BYTES,n,k); }
int crypto_stream(unsigned char *out, unsigned long long outlen, const unsigned char *n,const unsigned char *k) { return crypto_stream_xor(out, NULL, outlen, n, k); }
int _tmain(int argc, _TCHAR* argv[]) { if (sodium_init() == -1) { _tprintf(_T("Could not initialize cryptography subsystem!\n")); return 1; } if (argc < 3) { _tprintf(_T("usage: cryptfile [-d] [-o <outfile>] <password> <file>\n")); _tprintf(_T("where\n")); _tprintf(_T("\t-o <outfile> filename for non inplace encryption\n")); _tprintf(_T("\t-d decrypt file\n")); return 1; } bool bDecrypt = false; bool bUseTempFile = true; TCHAR szSourceFile[MAX_PATH]; TCHAR szTargetFile[MAX_PATH]; for (int i = 1; i < argc - 2; i++) { if (_tcscmp(_T("-d"), argv[i]) == 0) bDecrypt = true; if (_tcscmp(_T("-o"), argv[i]) == 0) { _tcscpy_s(szTargetFile, MAX_PATH, argv[i + 1]); bUseTempFile = false; } } if (bUseTempFile) { _tcscpy_s(szTargetFile, MAX_PATH, argv[argc - 1]); _tcscpy_s(szSourceFile, MAX_PATH, argv[argc - 1]); _tcscat_s(szSourceFile, MAX_PATH, _T(".tmp")); if (!::MoveFile(szTargetFile, szSourceFile)) { _tprintf(_T("File access denied: %s\n"), szTargetFile); return 1; } } else { _tcscpy_s(szSourceFile, MAX_PATH, argv[argc - 1]); } unsigned char pKey[crypto_stream_KEYBYTES]; unsigned char pNonce[crypto_stream_NONCEBYTES]; unsigned char pSalt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; // generate simple password salt (unique for this application) for (size_t i = 2; i < crypto_pwhash_scryptsalsa208sha256_SALTBYTES; i++) pSalt[i] = (i * 2) & 0xFF; pSalt[0] = 'C'; pSalt[1] = 'S'; // generate key (derived from password) crypto_pwhash_scryptsalsa208sha256( pKey, sizeof(pKey), reinterpret_cast<const char*>(argv[argc - 2]), _tcslen(argv[argc - 2]) * sizeof(TCHAR), pSalt, crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE, crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE); HANDLE hSourceFile = ::CreateFile(szSourceFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hSourceFile == INVALID_HANDLE_VALUE) { _tprintf(_T("File access denied: %s\n"), szSourceFile); return 1; } HANDLE hTargetFile = ::CreateFile(szTargetFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hTargetFile == INVALID_HANDLE_VALUE) { ::CloseHandle(hSourceFile); _tprintf(_T("File access denied: %s\n"), szTargetFile); return 1; } BYTE *pData = new BYTE[CHUNK_SIZE]; DWORD dwBytesRead = 0; DWORD dwBytesWritten = 0; if (bDecrypt) { // load file unique number for decryption ::ReadFile(hSourceFile, pNonce, sizeof(pNonce), &dwBytesRead, NULL); } else { // generate number to used once (unique for each file) randombytes_buf(pNonce, sizeof(pNonce)); ::WriteFile(hTargetFile, pNonce, sizeof(pNonce), &dwBytesWritten, NULL); } while (::ReadFile(hSourceFile, pData, CHUNK_SIZE, &dwBytesRead, NULL) && dwBytesRead > 0) { crypto_stream_xor(pData, pData, dwBytesRead, pNonce, pKey); // inplace ::WriteFile(hTargetFile, pData, dwBytesRead, &dwBytesWritten, NULL); } delete[] pData; ::CloseHandle(hTargetFile); ::CloseHandle(hSourceFile); if (bUseTempFile) ::DeleteFile(szSourceFile); #ifdef _DEBUG _tsystem(_T("pause")); #endif return 0; }