Generate 33 bytes public key for curve25519 in python - private-key

Using Java's spongycastle, i am able to generate curve25519 private keys(32 bytes) and public keys(33 bytes).
Similarly for Python, i am using Nacl library for curve25519 but here public key generated is of 32 bytes only. The one byte of y co-ordinate is missing in public key.
from nacl.public import PrivateKey
import binascii
privKey = PrivateKey.generate()
pubKey = privKey.public_key
print("privKey:", binascii.hexlify(bytes(privKey)))
print("pubKey: ", binascii.hexlify(bytes(pubKey)))
any suggestion why Nacl library is not compressing the public key ?

spongycastle(Java) and PyNacl(Python) are totally two different libraries.
PyNacl(Python) and LazySodiumJava(Java) derive from C library libsodium, they can only generate 32bit key.
I think maybe you could look for other Python packages, which is consistent with spongycastle(Java).

Related

Python passlib generate one time secret code

What is the easiest way to generate a one-time password (sms secret code with N lengths of symbols) with passlib?
How I'm creating it now:
from secrets import randbelow as secrets_randbelow
def create_secret_code() -> str: # TODO use OTP
secret_code = "".join([str(secrets_randbelow(exclusive_upper_bound=10)) for _ in range(config.SECRET_CODE_LEN)])
print_on_stage(secret_code=secret_code)
return secret_code
Obviously, it needs to check that generated code already not in a use (for example - making it via Redis).
I also already have an passlib object into my code to hashing and verifying passwords
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
I found this class, but can't figure out how to just generate sms secret code with N lengths of symbols
P.S. I added a fastapi tag because I'm using an fastapi and passlib is used as standard cryptography tool for it, docs
You can initialize the TOTP class with the number of digits you want for the token, like this:
TOTP(digits=10)
Here's a complete example, using your config.SECRET_CODE_LEN:
from passlib.totp import TOTP
otp = TOTP('s3jdvb7qd2r7jpxx', digits=config.SECRET_CODE_LEN)
token = otp.generate()
print(token.token)

Play AES encrypted video in ExoPlayer offline

I am trying to play from local storage an encrypted video using ExoPlayer.
The command used to encrypt the video using FFMPEG is as follows:
-i /storage/emulated/0/Download/20210125_193031.mp4 -vcodec copy -acodec copy -c:v libx264 -encryption_scheme cenc-aes-ctr -encryption_key b42ca3172ee4e69bf51848a59db9cd13 -encryption_kid 09e367028f33436ca5dd60ffe6671e70 /storage/emulated/0/Download/out_enc.mp4
Here it is the sourcecode of my player:
public class PlayerActivity extends AppCompatActivity {
private SimpleExoPlayer player;
private DefaultDrmSessionManager drmSessionManager;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
// Build the media item.
PlayerView playerView = findViewById(R.id.video_view);
player = new SimpleExoPlayer.Builder(this).build();
playerView.setPlayer(player);
//player.prepare();
//FFMPEG command: -i /storage/emulated/0/Download/20210125_193031.mp4 -vf scale=-1:720 -c:v libx264 -encryption_scheme cenc-aes-ctr -encryption_key b42ca3172ee4e69bf51848a59db9cd13 -encryption_kid 09e367028f33436ca5dd60ffe6671e70 /storage/emulated/0/Download/out_enc.mp4
//base 64 keys generated from: https://www.base64encode.org/
//playVideo("/storage/emulated/0/Download/out_enc.mp4", "MDllMzY3MDI4ZjMzNDM2Y2E1ZGQ2MGZmZTY2NzFlNzA=", "YjQyY2EzMTcyZWU0ZTY5YmY1MTg0OGE1OWRiOWNkMTM=");
playVideo("/storage/emulated/0/Download/out_enc.mp4", "CeNnAo8zQ2yl3WD/5mcecA", "tCyjFy7k5pv1GEilnbnNEw");
}
private void playVideo(String url, String keyID, String keyValue) {
try {
drmSessionManager = buildDrmSessionManager(Util.getDrmUuid(C.CLEARKEY_UUID.toString()), true, keyID, keyValue
);
} catch (Exception e) {
e.printStackTrace();
}
player.setMediaSource(buildDashMediaSource(Uri.parse(url)));
player.prepare();
player.setPlayWhenReady(true);
}
private MediaSource buildDashMediaSource(Uri uri) {
DefaultDataSourceFactory dashChunkSourceFactory = new DefaultDataSourceFactory(this, "agent");
return new ProgressiveMediaSource.Factory(dashChunkSourceFactory)
.setDrmSessionManager(drmSessionManager)
.createMediaSource(uri);
}
private DefaultDrmSessionManager buildDrmSessionManager(UUID uuid, Boolean multiSession, String id, String value) {
/* String base64Id = Base64.encodeToString(id.getBytes(), Base64.DEFAULT);
String base64Value = Base64.encodeToString(value.getBytes(), Base64.DEFAULT);*/
String keyString = "{\"keys\":[{\"kty\":\"oct\",\"k\":\""+value+"\",\"kid\":\""+id+"\"}],\"type\":\"temporary\"}";;
LocalMediaDrmCallback drmCallback = new LocalMediaDrmCallback(keyString.getBytes());
FrameworkMediaDrm mediaDrm = null;
try {
mediaDrm = FrameworkMediaDrm.newInstance(uuid);
} catch (UnsupportedDrmException e) {
e.printStackTrace();
}
return new DefaultDrmSessionManager(uuid, mediaDrm, drmCallback, null, multiSession);
}
#Override
protected void onDestroy() {
player.release();
super.onDestroy();
}
Here it is the link for the encrypted video.
The main issue: the video is playing but is not decrypted. What am I missing?
Looking at the logcat output there does not seem to be any DRM, AES or clearkey errors.
Looking then at the video file itself, it appears to report some issues:
However, checking against other sample files encrypted using he same ffmpeg approach you used, they show similar issues so this appear to be typical output from ffprobe for a file encrypted in this way.
Looking then at the video file structure itself with an MP4 parser to see the individual atoms, or the header blocks, there does not appear to be a PSSH box.
A PSSH box is a header area that contains the data about the encryption for an ISOBMFF mp4 file - this is actually an optional field in the CENC spec so your video is valid even without this.
The obvious question then is, how would a player know the video is encoded? The answer, according to the CENC spec is:
Detection
For a stream determined to be in the ISO Base Media File Format [ISOBMFF], this ISO Common Encryption ('cenc') Protection Scheme may be detected as follows.
Protection scheme signaling conforms with [ISOBMFF]. When protection has been applied, the stream type will be transformed to 'encv' for video or 'enca' for audio, with a Protection Scheme Information Box ('sinf') added to the sample entry in the Sample Description Box ('stsd'). The Protection Scheme Information Box ('sinf') will contain a Scheme Type Box ('schm') with a scheme_type field set to a value of 'cenc'
Looking at your video using a MP4 analyser (see below) shows that it does indeed have the stream type shown as 'encv' in the stud box (output from inspect tool below):
Testing playback with ffplay itself using the same encryption key, shows that the video does actually play successfully:
ffplay out_enc.mp4 -decryption_key b42ca3172ee4e69bf51848a59db9cd13
However, a regular player will not be able to play it unless you provide the decryption key. It would be reasonable to to expect the player to flag an error in this case, but that does not appear to be happening with some common players I checked including VLC, so it is quite possible ExoPlayer on Android is not flagging this also.
Looking at ExoPlayer specifically, as noted by Duna in the comments below and outlined in this GIT thread https://github.com/google/ExoPlayer/issues/8532#issuecomment-771811707 , ExoPlayer does not currently (Feb 2021) read the PSSH box for MP4, only for fragmented MP4. From that thread:
After looking deeper into this, I found that ExoPlayer's Mp4Extractor actually doesn't read pssh boxes. Currently we only read this info in fragmented MP4 files (using FragmentedMp4Extractor). This means even when playing the file with the pssh box, the drmInitData still ends up null - meaning playback fails. I didn't realise this limitation when you initially filed the issue, otherwise I would have flagged it earlier.
However, looking at the Mp4Extractor code it does check for 'encv' and it does also check for the default key_id, both of which are present in the video file produced when inspected. Again, it would be reasonable for ExoPlayer to flag an error if it either does not find these in a format is can understand, or if it finds them but is not supplied a corresponding key to play the file with.
So how could the video be encrypted and played reliably?
You could use ffplay on android although I suspect this would not be too straightforward, based on past experience using ffmpeg on Android.
There are some easier (appearing) examples leveraging ExoPlayer also that it would be worth looking at - e.g:
https://stackoverflow.com/a/62678769/334402
You could also look at leveraging DASH. Most media that is streamed to mobile devices these days use a streaming protocol like DASH or HLS - these formats will nearly always have the encryption data included in the 'manifest' or 'index' file and this will definitely be recognised by ExoPlayer. There are online tutorials and free tools to allow you package videos into DASH, including adding encryption. The ExoPlayer team provide information on downloading and playing back such these streams (link correct at time of writing):
https://exoplayer.dev/downloading-media.html
If you want to examine the mp4 files yourself in more detail there are various free tools like:
https://gpac.github.io/mp4box.js/test/filereader.html (highlighted by Duna in comments and looks very good)
https://www.bento4.com/documentation/mp4dump/
https://inspect.eyevinn.technology

FIPS_mode_set function affects encryption

To the best of my knowledge OpenSSL's function FIPS_mode_set should not affect encryption. All it does is terminating the program if a weak cipher is used.
I have a piece of code that uses EVP_aes_128 encryption:
EVP_CIPHER_CTX ctx;// = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(&ctx);
const EVP_CIPHER *cipher = EVP_aes_128_cbc();
EVP_EncryptInit(&ctx, cipher, key, IV);
EVP_CIPHER_CTX_set_padding (&ctx, 0);
EVP_EncryptUpdate(&ctx, encrypted.get(), &encrypted_size, paddedPlain.get(), encrypted_size);
return encrypted;
This code is consistent (I get the same output on every run) and working always as expected (decryption function is decrypting it back with no problems). But when I call FIPS_mode_set(1) on the beginning of the run, I get an inconsistent (different output on every run) output in the output buffer.
the input IV:
the key file:
the input text:
the encryption output without 'FIPS_mode_set'(1):
the encryption output with 'FIPS_mode_set'(1):
I'm using OpenSSL version 1.0.2k.
What could possibly cause such behavior?
You're not using the API correctly, as you are forgetting to call EVP_EncryptFinal_ex(). FIPS mode has more stringent requirements with regards to clearing buffers, so maybe that's why you don't get any ciphertext back before the call to EVP_EncryptFinal_ex() - which you don't seem to use.
Furthermore, you are using obsolete functions:
The functions EVP_EncryptInit(), EVP_EncryptFinal(), EVP_DecryptInit(), EVP_CipherInit() and EVP_CipherFinal() are obsolete but are retained for compatibility with existing code. New code should use EVP_EncryptInit_ex(), EVP_EncryptFinal_ex(), EVP_DecryptInit_ex(), EVP_DecryptFinal_ex(), EVP_CipherInit_ex() and EVP_CipherFinal_ex() because they can reuse an existing context without allocating and freeing it up on each call.
Please make sure you keep as much as possible to the examples in the OpenSSL (EVP) Wiki.

Is it possible to use AES CTR mode encryption using the EVP API?

I'm new to OpenSSL. I understand that encryption should be performed using the EVP API which acts as a common interface to all the ciphers. AES CTR mode seems to be present in the version of OpenSSL that I have, but the definition for EVP_aes_128_ctr is disabled in evp.h:
#if 0
const EVP_CIPHER *EVP_aes_128_ctr(void);
#endif
Any idea why this is? Can I just remove the #if 0? Any other pointers on getting 128 bit AES CTR mode encryption to work in OpenSSL would be appreciated!
Thanks!
Btw, it looks like the answer to this is no, not yet. But maybe soon. I found this email thread indicating that a patch to address this issue may have been submitted in June 2010:
http://www.mail-archive.com/libssh2-devel#cool.haxx.se/msg01972.html
But when I downloaded the latest development branch from SVN, AES CTR was still not enabled in EVP. I ended up just implementing it directly, for which I found this link helpful:
AES CTR 256 Encryption Mode of operation on OpenSSL
I'm using AES CTR 128 mode and it works. I'm using libssl1.0.0 (I'm not sure if I'm answering the right question! I hope it would be helpful).
Here is a part of my code:
EVP_CipherInit_ex(ctx, EVP_aes_128_ctr(), NULL, key, iv,1);
EVP_CipherUpdate (ctx, ciphertext, &len, plaintext, plaintext_len);
/* Finalise the encryption. */
if(! EVP_CipherFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
/*setting padding option*/
EVP_CIPHER_CTX_set_padding(ctx,0);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);

UUIDs and byte-swapping over network

Is there are a standard accepted way to byte-swap UUIDs for transmission over a network (or file storage)? (I want to send/store the 16 raw bytes rather than convert the UUID to a string representation.)
I thought at first I should partition the UUID into 4 32-bit integers and call htonl on each of them, but that didn't smell right. A UUID has internal structure (from RFC 4122):
typedef struct {
unsigned32 time_low;
unsigned16 time_mid;
unsigned16 time_hi_and_version;
unsigned8 clock_seq_hi_and_reserved;
unsigned8 clock_seq_low;
byte node[6];
} uuid_t;
Would it be correct to do:
...
uuid.time_low = htonl( uuid.time_low );
uuid.time_mid = htons( uuid.time_mid );
uuid.time_hi_and_version = htons( uuid.time_high_and_version );
/* other fields are represented as bytes and shouldn't be swapped */
....
before writing, and then the correpsonding ntoh...calls after reading at the other end?
Thanks.
Yes, that is the correct thing to do.
Each number (time_low, time_mid, time_hi_and_version) are subject to byte ordering. the node field is not. clock_seq_hi_and_reserved and clock_seq_low are also subject to byte ordering, but they are each one byte, so it doesn't matter.
Of course, it is up to you to make sure that you choose the right ordering on both ends, or understand what the ordering is on the other end if you don't control it. Microsoft of course uses little endian for their UUIDs. You can see Microsoft's definition of a UUID here.

Resources