/r/crypto
Cryptography is the art of creating mathematical assurances for who can do what with data, including but not limited to encryption of messages such that only the key-holder can read it. Cryptography lives at an intersection of math and computer science.
This is a technical subreddit covering the theory and practice of modern and strong cryptography.
... is the art of creating mathematical / information theoretic assurances for who can do what with data, including but not limited to the classical example of encrypting messages so that only the key-holder can read it. Cryptography lives at an intersection of math and computer science.
This subreddit is intended for links and discussions surrounding the theory and practice of modern and strong cryptography.
Please note that this subreddit focused on the tech, not politics! The focus is on the algorithms and the security of the implementations.
Because this subreddit currently is in restricted mode, you will NOT be able to post or comment before your account has been approved. Send us a reason for why you want to join via mod mail, click here and tell us why you want to discuss cryptography;
https://www.reddit.com/message/compose/?to=/r/crypto
(along with normal reddiquette)
Don't forget to read our RULES PAGE! The rules listed there are also used as this sub's report reasons. The quick version;
Internal:
External:
Other subreddits that may be of interest:
Theory:
Practical:
Educational, hobbyist:
Political and in the news:
Software:
Related:
Memes and low effort submissions:
Feel free to message the moderators with suggestions for how to improve this subreddit, as well as for requesting adding links in the sidebar.
/r/crypto
I've mentioned it to people and they look at me like I have three heads or something. The setup involves group G, and a non-commuting subgroup H, where H≤G. This naturally aligns with random matrices as matrix multiplication is order dependent. Let's say we have public matrix A and hidden matrix U, AU ≠ UA and we can extend this to t'=AUx ≠ t=UAx. Then we can we have group G that comprises all t' and t elements in both AUx and UAx.
The group operation is matrix multiplication, and subgroup UAx is H. Half of the complexity comes from the inability to distinguish elements in H from elements in G in general. Next we include some kind of hiding function f() that creates equivalence classes out of the elements in G. This hiding function defines and maps cosets from both to the same output.
This problem, when properly instantiated, very hard to solve as an adversary attempting to invert f() gets a result with no way to distinguish if came from a coset under H or under G, it is indistinguishable.
Does any of this ring a bell with the cryptographic community or is this something only quantum researchers are working on? I'm trying to calibrate how I speak about this construction to cryptographers.
Welcome to /r/crypto's weekly community thread!
This thread is a place where people can freely discuss broader topics (but NO cryptocurrency spam, see the sidebar), perhaps even share some memes (but please keep the worst offenses contained to /r/shittycrypto), engage with the community, discuss meta topics regarding the subreddit itself (such as discussing the customs and subreddit rules, etc), etc.
Keep in mind that the standard reddiquette rules still apply, i.e. be friendly and constructive!
So, what's on your mind? Comment below!
I want to get a PhD in CS or Applied Math related to cryptography, specifically in codebreaking. Next year, I can either take Measure-Theoretic Probability Theory + Graduate Real Analysis or Category Theory/Homological Algebra + Analytical Number Theory. Which one should I pick?
I insert myself between two internet routers, reading and injecting data layer packets. It helps if I am near a CA server.
For each IP address, I make an HTTP-01 ACME challenge. For each IP address, a response from a CA will get routed through my cable. I add the challenge file to my server so the CA can GET request it, and sign my CSR.
I now have a server with an SSL certificate and key for every IP address. This shows up in CA logs.
What stops this happening?
CTR mode and it's derivatives(like GCM) has an issue with key commitment. An attacker can convince a user to decrypt a given plaintext under multiple keys. For CTR mode, this is trivial since CTR mode provides no authentication at all. For modes that use a polynomial hash to provide authenticated encryption functionality like GCM, there exists attacks that allow an attacker to generate multiple keys for a given nonce-ciphertext-tag tuple.
I believe there is a simple countermeasure that ensures key commitment. The modification required is simple. We simply output the first block of the CTR mode during encryption and prepend it to the ciphertext. During decryption, we verify that the first block of the ciphertext matches the first output block of CTR mode. If this block matches, we proceed with decryption(or authentication and then decryption for modes like GCM).
In effect, the modified modes look like this:
# NOTE: No concerns are made for timing safety
# These two functions are just plain CTR mode with key commitment enhancement
def encrypt(nonce, key, plaintext_blocks):
sequence_iterator = counter.start(nonce)
ciphertext_blocks = []
first_block = Enc(sequence_iterator.value(), key)
sequence_iterator.increment()
ciphertext_blocks.append(first_block)
for plaintext_block in plaintext_blocks:
keystream_block = Enc(sequence_iterator.output_value(), key)
sequence_iterator.increment()
ciphertext_block = XOR(plaintext_block, keystream_block)
ciphertext_blocks.append(ciphertext_block)
return(ciphertext_blocks)
def decrypt(nonce, key, ciphertext_blocks):
sequence_iterator = counter.start(nonce)
plaintext_blocks = []
expected_first_block = Enc(sequence_iterator.value(), key)
sequence_iterator.increment()
stream_first_block = ciphertext_blocks[0]
if stream_first_block != expected_first_block:
raise Error
plaintext_blocks = []
for ciphertext_block in ciphertext_blocks[1::]:
keystream_block = Enc(sequence_iterator.output_value(), key)
sequence_iterator.increment()
plaintext_block = XOR(ciphertext_block, keystream_block)
plaintext_blocks.append(plaintext_block)
return(plaintext_blocks)
# These two functions represent the AEAD derivatives of CTR mode like GCM
def encrypt_AEAD((nonce, key, plaintext_blocks):
sequence_iterator = counter.start(nonce)
ciphertext_blocks = []
first_block = Enc(sequence_iterator.value(), key)
sequence_iterator.increment()
ciphertext_blocks.append(first_block)
# Modify this bit as much as needed until enough material is available for the authenticator in use
# Normally that is just a single block
authenticator_key = Enc(sequence_iterator.value(), key)
sequence_iterator.increment()
# Prepare the authenticator now
authenticator.init(authenticator_key)
authenticator.ingest(first_block)
for plaintext_block in plaintext_blocks:
keystream_block = Enc(sequence_iterator.output_value(), key)
sequence_iterator.increment()
ciphertext_block = XOR(plaintext_block, keystream_block)
authenticator.ingest(ciphertext_block)
ciphertext_blocks.append(ciphertext_block)
authenticator_tag = authenticator.finalize_and_emit_tag()
return(ciphertext_blocks, authenticator_tag)
def decrypt_AEAD(nonce, key, ciphertext_blocks, authenticator_tag):
sequence_iterator = counter.start(nonce)
expected_first_block = Enc(sequence_iterator.value(), key)
sequence_iterator.increment()
stream_first_block = ciphertext_blocks[0]
if stream_first_block != expected_first_block:
raise Error
# Modify this bit as much as needed until enough material is available for the authenticator in use
# Normally that is just a single block
authenticator_key = Enc(sequence_iterator.value(), key)
sequence_iterator.increment()
# Prepare the authenticator now
authenticator.init(authenticator_key)
authenticator.ingest(stream_first_block)
plaintext_blocks= []
for ciphertext_block in ciphertext_blocks[2::]:
keystream_block = Enc(sequence_iterator.output_value(), key)
sequence_iterator.increment()
plaintext_block = XOR(ciphertext_block , keystream_block)
authenticator.ingest(ciphertext_block)
plaintext_blocks.append(plaintext_block)
expected_authenticator_tag = authenticator.finalize_and_emit_tag()
if authenticator_tag != expected_authenticator_tag:
raise Error
return(plaintext_blocks)
My question is the following: Does this modification actually add key commitment and prevent invisible salamander attacks? My intuition for this property is that the CTR mode variant doesn't quite get to a complete proof(treating the block cipher as a PRF doesn't mean much since the attacker gets to control the key to said PRF, we'd need to model the block cipher as a random oracle instead). However, this might be provably secure for the AEAD mode variants like GCM or CTR+Poly-1305.
PS: This can also be used for Salsa/ChaCha20 as well. In that case we can just skip the step where we convert the "block cipher" from a PRP into a PRF because the stream cipher itself is effectively a keyed PRF.
So I'm tasked to convert an AES encryption code from Javascript using CryptoJS to Kotlin using Cipher.
CryptoJS.AES.encrypt(loadb64, key).toString()
All is going well and I came up with this code:
fun encryptAES(loadb64: String, key: String): String {
val secretKey = SecretKeySpec(key, "AES")
val iv = ByteArray(16) val ivSpec = IvParameterSpec(iv)
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec)
val encryptedBytes = cipher.doFinal(loadb64.toByteArray(Charsets.UTF_8))
return Base64.getEncoder().encodeToString(encryptedBytes) }
However when I tested it, the result has a different length compared to the javascript code.
It turns our, the key being passed to the JS code is 64 bytes which obviously isnt allowed for AES yet its not throwing an error.
So my question is, how does CryptoJS handle a key of 64 bytes? Does it truncate or hash it?
Welcome to /r/crypto's weekly community thread!
This thread is a place where people can freely discuss broader topics (but NO cryptocurrency spam, see the sidebar), perhaps even share some memes (but please keep the worst offenses contained to /r/shittycrypto), engage with the community, discuss meta topics regarding the subreddit itself (such as discussing the customs and subreddit rules, etc), etc.
Keep in mind that the standard reddiquette rules still apply, i.e. be friendly and constructive!
So, what's on your mind? Comment below!
I'm working on a new product that will have mobile phone apps as some clients, but due to timeliness and usage patterns I want long term auth of some kind. A refresh once per quarter or so would be ideal.
I could use JWT into this with a 3 month refresh token, but with a flaky network that would take two requests and that could be two slow. I could use JWT with a 3 month long access token, but that feels like crowbaring JWT into being something it's not meant to be. What I've seen previously is access token lifetimes of 2 hours or so.
I've been pondering some sort of api keys, signed key blobs sent with the request etc. But then I realized that maybe there's already a proper scheme for my use case before I go sketching out something...drumwhirl...sketchy.
So, to be concrete, I'm wondering if there's a scheme fitting these requirements:
Feel free to ask for more details if it'll help, I'm still trying to figure them out myself. Otherwise, anyone got suggestions?
Hello!
i am a Ham radio operator and i want to experiment sending encrypted traffic* using JS8call. its a program sending/receiving UPPERCASE letters or numbers at about 8-40WPM. i need a something using symmetrical encryption that i can easily copy and paste text out off. JS8call already has checksum inside that enable the users to automatically see if the message is intact or not. so i dont need signatures, verification and stuff.
if possible compatible with Windows and Linux? with a GUI
i searched alot online for hours without sucess. it seem i need something that can convert the output to HEX (also recognize this to decode). there is alot of very interesting stuff on Github, but its mostly webpage based or command line. i wish somebody knows of an existing solution.
*encryption on Ham bands is legal in my country. i just need to make public the mode and password used.
See the title.
The rule is being applied due to multiple cases of users coming to us with extremely incorrect ideas about cryptography which they got from LLMs such as ChatGPT, wasting time and causing frustration because they assumed ChatGPT told the truth.
Any use of any LLM, AI, neural network, or other machine learning architecture, or any equivalent computer generated response, MUST be disclosed. You must also disclose the prompt so that we can understand what you're trying to achieve and why.
I am going to ask a rather stupid question for which I apologize in advance, but I'm sort of losing my head at this point.
I am working on an encryption system where two parties are required to authenticate themselves to one another and subsequently perform a key exchange.
The procedure is as follows:
Now let's say a malicious actor, Charlie wants to authenticate his public key to Bob, and Charlie has managed to intercept the signature sent by Alice.
Can Charlie destroy Alice's original signature, sign the token with his own key, and "replay" it to Bob?
If this is possible, how can one avoid such a situation?
Edit: So it turns out there's a term for exactly what I was trying to achieve, called PAKE. Thanks to u/cryptoam1, u/Natanael_L, and u/djao for pointing it out, and sorry for asking a question without first doing thorough research, but I ended up learning something new. Reddit goated as always!
Dear r/crypto community,
I wanted to reach out and apologize for removing my recent post about AMBER256. Upon reflection, I realized that I currently lack the necessary expertise to develop a robust cryptographic algorithm. My intention was never to spread an unsound or insecure algorithm, and I believe it's important to prevent the dissemination of potentially flawed cryptographic methods.
Before I revisit this project, I plan to dedicate significant time to studying existing implementations and understanding possible attacks. My goal is to ensure that any future contributions I make are both meaningful and secure.
I am sincerely sorry for any confusion or inconvenience this may have caused. I also want to thank everyone who offered support and constructive feedback. Your insights are invaluable, and I appreciate your understanding.
Thank you for your patience, and I look forward to engaging with the community again once I have gained more knowledge in this field.
Hello everyone. Some time ago I created efficient pseudo-random number generators based on Collatz-like functions:
https://www.reddit.com/r/RNG/comments/19a2q24/collatzweyl_generators/
https://arxiv.org/pdf/2312.17043
One of the simplest of them is the Collatz-Weyl generator:
static __uint128_t x, weyl, s; // s must be odd
bool Collatz_Weyl(void){
if(x % 2 == 1){
x = (3*x+1)/2;}
else{
x = x/2;}
x ^= (weyl += s);
return x & 1;
}
We can consider s
as a key and the resulting single bit could be used as a cryptographically secure bit to XOR with plaintext, as in a typical strem cipher. Every iteration of presented function generate only 1 bit, similar to Blum Blum Shub. It can be used as a extremely light-weight stream cipher, the whole code is just (constant-time implementation):
x = (-(x & 1) & (x + ((x + 1) >> 1)) | ~-(x & 1) & (x >> 1)) ^ (weyl += s);
return x & 1;
In the linked thread I provide a certain method of attack, when XORation with weyl sequence is replaced by addition (toy version), using extended Euclidean algorithm and by hacking somehow at least some bits of the key or the state of the generator. In the main version using XOR, such an attack is not even possible. I did not consider any other types of attacks than those mentioned here, i.e.:
- dedicated type of attack based on known-plaintext attack on toy version,
- related key attacks,
- timing attacks,
- theoretically possible birthday attacks (see my comment in this thread).
Perhaps such a stream cipher could find applications on extremely resource-constrained devices. However, I don't know if I'll find the motivation to write a separate paper on this topic and if it's even worth it. I don't feel competent enough in the subject of cryptography (so I probably won't take on this task alone), I wasn't even able to get the opinion of anyone from the industry (it's a pretty closed industry, and I don't come from the crypto industry, I did it as a hobby).
Here is constant-time code, with some additional measures to prevent related-key attacks and to fill the key:
#include <bitset>
#include<iostream>
//the initializer is there to fill the entire key s, additionally initializing s in this way helps to avoid recognizing keys with the same number of zeros, e.g. by adding 2^n to the key, which is important for the security of the algorithm, because it can lead to the generation of weaker x; this initialization is also to prevent key from being determined by simple modulo subtraction from weyl, if an attacker were to for example hack s and weyl, he could determine an initial value of weyl which in this case would not lead him to key
struct xws { __uint128_t x, weyl, s; };
struct xws initializer(__uint128_t x_init, __uint128_t weyl_init, const __uint128_t s_init)
{
__uint128_t x = 0;
__uint128_t weyl = 0;
__uint128_t s = 0;
for (int i = 0; i < 128; i++)
{
x_init = (-(x_init & 1) & (x_init + ((x_init + 1) >> 1)) | ~- (x_init & 1) & (x_init >> 1)) ^ (weyl_init += s_init);
x += (x_init & 1) << i;
}
for (int i = 0; i < 128; i++)
{
x_init = (-(x_init & 1) & (x_init + ((x_init + 1) >> 1)) | ~- (x_init & 1) & (x_init >> 1)) ^ (weyl_init += s_init);
weyl += (x_init & 1) << i;
}
for (int i = 0; i < 128; i++)
{
x_init = (-(x_init & 1) & (x_init + ((x_init + 1) >> 1)) | ~- (x_init & 1) & (x_init >> 1)) ^ (weyl_init += s_init);
s += (x_init & 1) << i;
}
return xws{x, weyl, s | 1 };
}
struct xw { __uint128_t x, weyl; };
//skip is to avoid correlated bitstream results for consecutive s, given the same x and weyl or for example for consecutive weyl, given the same s and x, etc.
struct xw skip(__uint128_t x, __uint128_t weyl, const __uint128_t s)
{
for (int i = 0; i < 128; i++)
{
x = (-(x & 1) & (x + ((x + 1) >> 1)) | ~- (x & 1) & (x >> 1)) ^ (weyl += s);
}
return xw{ x, weyl };
}
__uint128_t next(__uint128_t& x, __uint128_t& weyl, const __uint128_t& s)
{
__uint128_t v = 0;
for (int i = 0; i < 128; i++)
{
x = (-(x & 1) & (x + ((x + 1) >> 1)) | ~-(x & 1) & (x >> 1)) ^ (weyl += s);
v += (x & 1) << i; // here we build 128-bit numbers from a single bit returned sequentially by the generator
}
return v;
}
int main()
{
const __uint128_t key = 12345678910111213; //the key must be odd
const __uint128_t x_init = key, weyl_init = key, s_init = key; //all these variables must be secret, s_init must be odd
xws initialization = initializer(x_init, weyl_init, s_init);
__uint128_t x = initialization.x;
__uint128_t weyl = initialization.weyl;
__uint128_t s = initialization.s;
xw skipping = skip(x, weyl, s);
x = skipping.x;
weyl = skipping.weyl;
__uint128_t result = 0;
for(int i=0; i<100; i++)
{
result = next(x, weyl, s);
std::cout << std::bitset<64>(result >> 64) << "\n";
std::cout << std::bitset<64>(result) << "\n";
}
return 0;
}
An additional feature is backtracking resistance, since it is not based on a bijective function, you must guess at least one bit in each iteration to reverse it, see: https://arxiv.org/abs/1801.05079. What do you think?
Welcome to /r/crypto's weekly community thread!
This thread is a place where people can freely discuss broader topics (but NO cryptocurrency spam, see the sidebar), perhaps even share some memes (but please keep the worst offenses contained to /r/shittycrypto), engage with the community, discuss meta topics regarding the subreddit itself (such as discussing the customs and subreddit rules, etc), etc.
Keep in mind that the standard reddiquette rules still apply, i.e. be friendly and constructive!
So, what's on your mind? Comment below!
This is another installment in a series of monthly recurring cryptography wishlist threads.
The purpose is to let people freely discuss what future developments they like to see in fields related to cryptography, including things like algorithms, cryptanalysis, software and hardware implementations, usable UX, protocols and more.
So start posting what you'd like to see below!
I'm a professional software engineer, and I've written software to manage user-generated keys for a bespoke system in the past. The general gist was vary the encoding of the key data itself while associating it with a human-readable label in a flat file that was subsequently encrypted before being written to disk, and encrypted in RAM, only after being fully loaded, by a key that was part of the key management program. That key was not stored in plaintext in the program executable. It was stored in chunks with about 10 x the actual amount of data needed to store the key, interspersed randomly, and only assembled together, programmaticly, and in random fashion, and decoded into the actual key immediately before it's needed, and as soon as the operation is over, it's memory is zeroed back out until the key is needed again. If anyone had the program source code, they could easily implement a new master key and create their own key ring eco-system, but it was the only way I could come up with to be able to store several keys persistently, but securely, while allowing the user to manage their own keys as they saw fit.
Surely, there are better ways to manage user keys. PGP has a keyring. GPG has a keyring. Even GNOME has a keyring. How are they designed to keep keys persistently, but securely? Are there any design documents or research papers that describe such a system?
Welcome to /r/crypto's weekly community thread!
This thread is a place where people can freely discuss broader topics (but NO cryptocurrency spam, see the sidebar), perhaps even share some memes (but please keep the worst offenses contained to /r/shittycrypto), engage with the community, discuss meta topics regarding the subreddit itself (such as discussing the customs and subreddit rules, etc), etc.
Keep in mind that the standard reddiquette rules still apply, i.e. be friendly and constructive!
So, what's on your mind? Comment below!
im working on a javascript UI framework for personal projects and im trying to create something like a React-hook that handles "encrypted at rest".
the react-hook is described in more detail here. id like to extend its functionality to have encrypted persistant data. my approach is the following and it would be great if you could follow along and let me know if im doing something wrong. all advice is apprciated.
im using indexedDB to store the data. i created some basic functionality to automatically persist and rehydrate data. im now investigating password-encrypting the data with javascript using the browser cryptography api.
i have a PR here you can test out on codespaces or clone, but tldr: i encrypt before saving and decrypt when loading. this seems to be working as expected. i will also encrypt/decrypt the event listeners im using and this should keep it safe from anything like browser extensions from listening to events.
the password is something the user will have to put in themselves at part of some init() process. i havent created an input for this yet, so its hardcoded. this is then used to encrypt/decrypt the data.
i would persist the unencrypted salt to indexedDB because this is then used to generate the key.
i think i am almost done with this functionality, but id like advice on anything ive overlooked or things too keep-in-mind. id like to make the storage as secure as possible.
---
Edit 11/11/2024:
I created some updates to the WIP pull-request. The behavior is as follows.
- The user is prompted for a password if one isn't provided programmatically.
- This will allow for developers to create a custom password prompts in their application. The default fallback is to use a JavaScript prompt().
- It also seems possible to enable something like "fingerprint/face encryption" for some devices using the webauthn api. (This works, but the functionality is a bit flaky and needs to be "ironed out" before rolling out.)
- Using AES-GCM with 1mil iterations of PBKDF2 to derive the key from the password.
- The iterations can be increased in exchange for slower performance. It isn't currently configurable, but it might be in the future.
- The salt and AAD need to be deterministic and so to simplify user input, the salt as AAD are derived as the sha256 hash of the password. (Is this a good idea?)
The latest version of the code can be seen in the PR: https://github.com/positive-intentions/dim/pull/9
The deadline to submit your presentation for FHE.org 2025 is fast approaching—less than two weeks left — November 23, 2024 (23:58 AoE)!
Don’t miss your chance to share your work with the FHE community in Sofia on March 25th, 2025.
We welcome a wide range of submissions, including work presented at other conferences, FHE-related use cases, innovative demos, tutorials, and any other thought-provoking FHE talk ideas.
Submit your work through our EasyChair server here: https://fhe.org/conferences/conference-2025/submissions
Submissions should be in the form of a 2-4 page PDF document that describes your work and highlights why it should be included in FHE.org 2025.
One of the main considerations for acceptance by our Program Committee is whether the talk will be of interest to the FHE audience.
For more details, check the full call for presentations: https://fhe.org/conferences/conference-2025/call-for-presentations