rtty-soda 0.2.1__py3-none-any.whl → 0.2.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of rtty-soda might be problematic. Click here for more details.

rtty_soda/cli_io.py CHANGED
@@ -64,25 +64,11 @@ def write_bytes_atomic(target: Path, data: bytes) -> None:
64
64
  temp_path.replace(target)
65
65
 
66
66
 
67
- def split_groups(data: str, group_len: int, line_len: int) -> str:
68
- step = group_len if group_len > 0 else line_len - 1
69
- groups = (data[i : i + step] for i in range(0, len(data), step))
70
- result: list[str] = []
71
- line: list[str] = []
72
- i = 0
73
- gpl = line_len // (step + 1)
74
- for group in groups:
75
- line.append(group)
76
- i += 1
77
- if i == gpl:
78
- result.append(" ".join(line))
79
- i = 0
80
- line = []
81
-
82
- if line:
83
- result.append(" ".join(line))
84
-
85
- return "\n".join(result)
67
+ def split_groups(data: str, group_len: int, line_len: int) -> tuple[str, int]:
68
+ step, gpl = group_len, line_len // (group_len + 1)
69
+ groups = [data[i : i + step] for i in range(0, len(data), step)]
70
+ lines = [" ".join(groups[i : i + gpl]) for i in range(0, len(groups), gpl)]
71
+ return "\n".join(lines), len(groups)
86
72
 
87
73
 
88
74
  def pad_newlines(data: str, count: int) -> str:
@@ -90,15 +76,21 @@ def pad_newlines(data: str, count: int) -> str:
90
76
  return padding + data.strip() + "\n" + padding
91
77
 
92
78
 
93
- def format_output(data: bytes, group_len: int, line_len: int, padding: int) -> bytes:
79
+ def format_output(
80
+ data: bytes, encoder: Encoder, group_len: int, line_len: int, padding: int
81
+ ) -> tuple[bytes, int]:
82
+ groups = 1
83
+ if encoder.is_binary:
84
+ return data, groups
85
+
94
86
  text = decode_bytes(data)
95
- if group_len > 0 or line_len > 0:
96
- text = split_groups(text, group_len, line_len)
87
+ if 0 < group_len < line_len:
88
+ text, groups = split_groups(text, group_len, line_len)
97
89
 
98
90
  if padding > 0:
99
91
  text = pad_newlines(text, padding)
100
92
 
101
- return encode_str(text)
93
+ return encode_str(text), groups
102
94
 
103
95
 
104
96
  def write_output(target: Path | None, data: bytes) -> None:
@@ -114,8 +106,8 @@ def write_output(target: Path | None, data: bytes) -> None:
114
106
  write_bytes_atomic(target, data)
115
107
 
116
108
 
117
- def print_stats(plaintext: bytes, ciphertext: bytes) -> None:
118
- click.echo(f"Plaintext: {len(plaintext)}", err=True)
119
- click.echo(f"Ciphertext: {len(ciphertext)}", err=True)
120
- overhead = len(ciphertext) / len(plaintext)
109
+ def print_stats(plaintext: int, ciphertext: int) -> None:
110
+ click.echo(f"Plaintext: {plaintext}", err=True)
111
+ click.echo(f"Ciphertext: {ciphertext}", err=True)
112
+ overhead = ciphertext / plaintext
121
113
  click.echo(f"Overhead: {overhead:.3f}", err=True)
rtty_soda/main.py CHANGED
@@ -40,13 +40,23 @@ def cli() -> None:
40
40
 
41
41
 
42
42
  @cli.command() # pyright: ignore[reportAny]
43
- @click.option("--encoding", "-e", default="base64", show_default=True)
43
+ @click.option(
44
+ "--encoding", "-e", default="base64", show_default=True, envvar="KEY_ENCODING"
45
+ )
44
46
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
45
- @click.option("--group-len", default=0, show_default=True)
46
- @click.option("--line-len", default=0, show_default=True)
47
- @click.option("--padding", default=0, show_default=True)
47
+ @click.option("--group-len", default=0, show_default=True, envvar="GROUP_LEN")
48
+ @click.option("--line-len", default=80, show_default=True, envvar="LINE_LEN")
49
+ @click.option("--padding", default=0, show_default=True, envvar="PADDING")
50
+ @click.option(
51
+ "--verbose", "-v", is_flag=True, envvar="VERBOSE", help="Show verbose output."
52
+ )
48
53
  def genkey_cmd(
49
- encoding: str, output_file: Path | None, group_len: int, line_len: int, padding: int
54
+ encoding: str,
55
+ output_file: Path | None,
56
+ group_len: int,
57
+ line_len: int,
58
+ padding: int,
59
+ verbose: bool,
50
60
  ) -> None:
51
61
  """Generate Private Key.
52
62
 
@@ -57,19 +67,27 @@ def genkey_cmd(
57
67
  key = bytes(PrivateKey.generate())
58
68
  key = enc.encode(key)
59
69
 
60
- if not enc.is_binary:
61
- key = format_output(key, group_len, line_len, padding)
70
+ formatted, groups = format_output(
71
+ data=key, encoder=enc, group_len=group_len, line_len=line_len, padding=padding
72
+ )
73
+ write_output(target=output_file, data=formatted)
62
74
 
63
- write_output(target=output_file, data=key)
75
+ if verbose:
76
+ click.echo(f"Groups: {groups}", err=True)
64
77
 
65
78
 
66
79
  @cli.command() # pyright: ignore[reportAny]
67
80
  @click.argument("private_key_file", type=in_path)
68
- @click.option("--encoding", "-e", default="base64", show_default=True)
81
+ @click.option(
82
+ "--encoding", "-e", default="base64", show_default=True, envvar="KEY_ENCODING"
83
+ )
69
84
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
70
- @click.option("--group-len", default=0, show_default=True)
71
- @click.option("--line-len", default=0, show_default=True)
72
- @click.option("--padding", default=0, show_default=True)
85
+ @click.option("--group-len", default=0, show_default=True, envvar="GROUP_LEN")
86
+ @click.option("--line-len", default=80, show_default=True, envvar="LINE_LEN")
87
+ @click.option("--padding", default=0, show_default=True, envvar="PADDING")
88
+ @click.option(
89
+ "--verbose", "-v", is_flag=True, envvar="VERBOSE", help="Show verbose output."
90
+ )
73
91
  def pubkey_cmd(
74
92
  private_key_file: Path,
75
93
  encoding: str,
@@ -77,6 +95,7 @@ def pubkey_cmd(
77
95
  group_len: int,
78
96
  line_len: int,
79
97
  padding: int,
98
+ verbose: bool,
80
99
  ) -> None:
81
100
  """Get Public Key.
82
101
 
@@ -89,20 +108,30 @@ def pubkey_cmd(
89
108
  pub = bytes(priv.public_key)
90
109
  pub = enc.encode(pub)
91
110
 
92
- if not enc.is_binary:
93
- pub = format_output(pub, group_len, line_len, padding)
111
+ formatted, groups = format_output(
112
+ data=pub, encoder=enc, group_len=group_len, line_len=line_len, padding=padding
113
+ )
114
+ write_output(target=output_file, data=formatted)
94
115
 
95
- write_output(target=output_file, data=pub)
116
+ if verbose:
117
+ click.echo(f"Groups: {groups}", err=True)
96
118
 
97
119
 
98
120
  @cli.command() # pyright: ignore[reportAny]
99
121
  @click.argument("password_file", type=in_path)
100
- @click.option("--encoding", "-e", default="base64", show_default=True)
101
- @click.option("--profile", "-p", default="sensitive", show_default=True)
122
+ @click.option(
123
+ "--encoding", "-e", default="base64", show_default=True, envvar="KEY_ENCODING"
124
+ )
125
+ @click.option(
126
+ "--profile", "-p", default="sensitive", show_default=True, envvar="KDF_PROFILE"
127
+ )
102
128
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
103
- @click.option("--group-len", default=0, show_default=True)
104
- @click.option("--line-len", default=0, show_default=True)
105
- @click.option("--padding", default=0, show_default=True)
129
+ @click.option("--group-len", default=0, show_default=True, envvar="GROUP_LEN")
130
+ @click.option("--line-len", default=80, show_default=True, envvar="LINE_LEN")
131
+ @click.option("--padding", default=0, show_default=True, envvar="PADDING")
132
+ @click.option(
133
+ "--verbose", "-v", is_flag=True, envvar="VERBOSE", help="Show verbose output."
134
+ )
106
135
  def kdf_cmd(
107
136
  password_file: Path,
108
137
  encoding: str,
@@ -111,6 +140,7 @@ def kdf_cmd(
111
140
  group_len: int,
112
141
  line_len: int,
113
142
  padding: int,
143
+ verbose: bool,
114
144
  ) -> None:
115
145
  """Key Derivation Function.
116
146
 
@@ -125,24 +155,35 @@ def kdf_cmd(
125
155
  key = kdf(password=pw, profile=prof)
126
156
  key = enc.encode(key)
127
157
 
128
- if not enc.is_binary:
129
- key = format_output(key, group_len, line_len, padding)
158
+ formatted, groups = format_output(
159
+ data=key, encoder=enc, group_len=group_len, line_len=line_len, padding=padding
160
+ )
161
+ write_output(target=output_file, data=formatted)
130
162
 
131
- write_output(target=output_file, data=key)
163
+ if verbose:
164
+ click.echo(f"Groups: {groups}", err=True)
132
165
 
133
166
 
134
167
  @cli.command(aliases=["e"]) # pyright: ignore[reportAny]
135
168
  @click.argument("private_key_file", type=in_path)
136
169
  @click.argument("public_key_file", type=in_path)
137
170
  @click.argument("message_file", type=in_path)
138
- @click.option("--key-encoding", default="base64", show_default=True)
139
- @click.option("--data-encoding", "-e", default="base64", show_default=True)
140
- @click.option("--compression", "-c", default="zstd", show_default=True)
171
+ @click.option(
172
+ "--key-encoding", default="base64", show_default=True, envvar="KEY_ENCODING"
173
+ )
174
+ @click.option(
175
+ "--data-encoding", "-e", default="base64", show_default=True, envvar="DATA_ENCODING"
176
+ )
177
+ @click.option(
178
+ "--compression", "-c", default="zstd", show_default=True, envvar="COMPRESSION"
179
+ )
141
180
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
142
- @click.option("--group-len", default=0, show_default=True)
143
- @click.option("--line-len", default=0, show_default=True)
144
- @click.option("--padding", default=0, show_default=True)
145
- @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
181
+ @click.option("--group-len", default=0, show_default=True, envvar="GROUP_LEN")
182
+ @click.option("--line-len", default=80, show_default=True, envvar="LINE_LEN")
183
+ @click.option("--padding", default=0, show_default=True, envvar="PADDING")
184
+ @click.option(
185
+ "--verbose", "-v", is_flag=True, envvar="VERBOSE", help="Show verbose output."
186
+ )
146
187
  def encrypt_public_cmd(
147
188
  private_key_file: Path,
148
189
  public_key_file: Path,
@@ -170,30 +211,44 @@ def encrypt_public_cmd(
170
211
  priv = PrivateKey(private_key=priv)
171
212
  pub = read_key_bytes(source=public_key_file, encoder=key_enc)
172
213
  pub = PublicKey(public_key=pub)
173
- data = stats = message_file.read_bytes()
174
- data = archiver(data)
214
+ plaintext = message_file.read_bytes()
215
+ data = archiver(plaintext)
175
216
  data = public.encrypt(private=priv, public=pub, data=data)
176
- data = data_enc.encode(data)
217
+ ciphertext = data_enc.encode(data)
177
218
 
178
- if not data_enc.is_binary:
179
- data = format_output(data, group_len, line_len, padding)
219
+ formatted, groups = format_output(
220
+ data=ciphertext,
221
+ encoder=data_enc,
222
+ group_len=group_len,
223
+ line_len=line_len,
224
+ padding=padding,
225
+ )
226
+ write_output(target=output_file, data=formatted)
180
227
 
181
- write_output(target=output_file, data=data)
182
228
  if verbose:
183
- print_stats(plaintext=stats, ciphertext=data)
229
+ print_stats(len(plaintext), len(ciphertext))
230
+ click.echo(f"Groups: {groups}", err=True)
184
231
 
185
232
 
186
233
  @cli.command(aliases=["es"]) # pyright: ignore[reportAny]
187
234
  @click.argument("key_file", type=in_path)
188
235
  @click.argument("message_file", type=in_path)
189
- @click.option("--key-encoding", default="base64", show_default=True)
190
- @click.option("--data-encoding", "-e", default="base64", show_default=True)
191
- @click.option("--compression", "-c", default="zstd", show_default=True)
236
+ @click.option(
237
+ "--key-encoding", default="base64", show_default=True, envvar="KEY_ENCODING"
238
+ )
239
+ @click.option(
240
+ "--data-encoding", "-e", default="base64", show_default=True, envvar="DATA_ENCODING"
241
+ )
242
+ @click.option(
243
+ "--compression", "-c", default="zstd", show_default=True, envvar="COMPRESSION"
244
+ )
192
245
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
193
- @click.option("--group-len", default=0, show_default=True)
194
- @click.option("--line-len", default=0, show_default=True)
195
- @click.option("--padding", default=0, show_default=True)
196
- @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
246
+ @click.option("--group-len", default=0, show_default=True, envvar="GROUP_LEN")
247
+ @click.option("--line-len", default=80, show_default=True, envvar="LINE_LEN")
248
+ @click.option("--padding", default=0, show_default=True, envvar="PADDING")
249
+ @click.option(
250
+ "--verbose", "-v", is_flag=True, envvar="VERBOSE", help="Show verbose output."
251
+ )
197
252
  def encrypt_secret_cmd(
198
253
  key_file: Path,
199
254
  message_file: Path,
@@ -217,30 +272,44 @@ def encrypt_secret_cmd(
217
272
  archiver = ARCHIVERS[compression]
218
273
 
219
274
  key = read_key_bytes(source=key_file, encoder=key_enc)
220
- data = stats = message_file.read_bytes()
221
- data = archiver(data)
275
+ plaintext = message_file.read_bytes()
276
+ data = archiver(plaintext)
222
277
  data = secret.encrypt(key=key, data=data)
223
- data = data_enc.encode(data)
278
+ ciphertext = data_enc.encode(data)
224
279
 
225
- if not data_enc.is_binary:
226
- data = format_output(data, group_len, line_len, padding)
280
+ formatted, groups = format_output(
281
+ data=ciphertext,
282
+ encoder=data_enc,
283
+ group_len=group_len,
284
+ line_len=line_len,
285
+ padding=padding,
286
+ )
287
+ write_output(target=output_file, data=formatted)
227
288
 
228
- write_output(target=output_file, data=data)
229
289
  if verbose:
230
- print_stats(plaintext=stats, ciphertext=data)
290
+ print_stats(len(plaintext), len(ciphertext))
291
+ click.echo(f"Groups: {groups}", err=True)
231
292
 
232
293
 
233
294
  @cli.command(aliases=["ep"]) # pyright: ignore[reportAny]
234
295
  @click.argument("password_file", type=in_path)
235
296
  @click.argument("message_file", type=in_path)
236
- @click.option("--kdf-profile", "-p", default="sensitive", show_default=True)
237
- @click.option("--data-encoding", "-e", default="base64", show_default=True)
238
- @click.option("--compression", "-c", default="zstd", show_default=True)
297
+ @click.option(
298
+ "--kdf-profile", "-p", default="sensitive", show_default=True, envvar="KDF_PROFILE"
299
+ )
300
+ @click.option(
301
+ "--data-encoding", "-e", default="base64", show_default=True, envvar="DATA_ENCODING"
302
+ )
303
+ @click.option(
304
+ "--compression", "-c", default="zstd", show_default=True, envvar="COMPRESSION"
305
+ )
239
306
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
240
- @click.option("--group-len", default=0, show_default=True)
241
- @click.option("--line-len", default=0, show_default=True)
242
- @click.option("--padding", default=0, show_default=True)
243
- @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
307
+ @click.option("--group-len", default=0, show_default=True, envvar="GROUP_LEN")
308
+ @click.option("--line-len", default=80, show_default=True, envvar="LINE_LEN")
309
+ @click.option("--padding", default=0, show_default=True, envvar="PADDING")
310
+ @click.option(
311
+ "--verbose", "-v", is_flag=True, envvar="VERBOSE", help="Show verbose output."
312
+ )
244
313
  def encrypt_password_cmd(
245
314
  password_file: Path,
246
315
  message_file: Path,
@@ -267,28 +336,42 @@ def encrypt_password_cmd(
267
336
 
268
337
  pw = read_password_bytes(password_file)
269
338
  key = kdf(password=pw, profile=prof)
270
- data = stats = message_file.read_bytes()
271
- data = archiver(data)
339
+ plaintext = message_file.read_bytes()
340
+ data = archiver(plaintext)
272
341
  data = secret.encrypt(key=key, data=data)
273
- data = data_enc.encode(data)
342
+ ciphertext = data_enc.encode(data)
274
343
 
275
- if not data_enc.is_binary:
276
- data = format_output(data, group_len, line_len, padding)
344
+ formatted, groups = format_output(
345
+ data=ciphertext,
346
+ encoder=data_enc,
347
+ group_len=group_len,
348
+ line_len=line_len,
349
+ padding=padding,
350
+ )
351
+ write_output(target=output_file, data=formatted)
277
352
 
278
- write_output(target=output_file, data=data)
279
353
  if verbose:
280
- print_stats(plaintext=stats, ciphertext=data)
354
+ print_stats(len(plaintext), len(ciphertext))
355
+ click.echo(f"Groups: {groups}", err=True)
281
356
 
282
357
 
283
358
  @cli.command(aliases=["d"]) # pyright: ignore[reportAny]
284
359
  @click.argument("private_key_file", type=in_path)
285
360
  @click.argument("public_key_file", type=in_path)
286
361
  @click.argument("message_file", type=in_path)
287
- @click.option("--key-encoding", default="base64", show_default=True)
288
- @click.option("--data-encoding", "-e", default="base64", show_default=True)
289
- @click.option("--compression", "-c", default="zstd", show_default=True)
362
+ @click.option(
363
+ "--key-encoding", default="base64", show_default=True, envvar="KEY_ENCODING"
364
+ )
365
+ @click.option(
366
+ "--data-encoding", "-e", default="base64", show_default=True, envvar="DATA_ENCODING"
367
+ )
368
+ @click.option(
369
+ "--compression", "-c", default="zstd", show_default=True, envvar="COMPRESSION"
370
+ )
290
371
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
291
- @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
372
+ @click.option(
373
+ "--verbose", "-v", is_flag=True, envvar="VERBOSE", help="Show verbose output."
374
+ )
292
375
  def decrypt_public_cmd(
293
376
  private_key_file: Path,
294
377
  public_key_file: Path,
@@ -313,24 +396,33 @@ def decrypt_public_cmd(
313
396
  priv = PrivateKey(private_key=priv)
314
397
  pub = read_key_bytes(source=public_key_file, encoder=key_enc)
315
398
  pub = PublicKey(public_key=pub)
316
- data = stats = read_bytes(source=message_file, encoder=data_enc)
317
- data = data_enc.decode(data)
399
+ ciphertext = read_bytes(source=message_file, encoder=data_enc)
400
+ data = data_enc.decode(ciphertext)
318
401
  data = public.decrypt(private=priv, public=pub, data=data)
319
- data = unarchiver(data)
402
+ plaintext = unarchiver(data)
403
+
404
+ write_output(target=output_file, data=plaintext)
320
405
 
321
- write_output(target=output_file, data=data)
322
406
  if verbose:
323
- print_stats(plaintext=data, ciphertext=stats)
407
+ print_stats(len(plaintext), len(ciphertext))
324
408
 
325
409
 
326
410
  @cli.command(aliases=["ds"]) # pyright: ignore[reportAny]
327
411
  @click.argument("key_file", type=in_path)
328
412
  @click.argument("message_file", type=in_path)
329
- @click.option("--key-encoding", default="base64", show_default=True)
330
- @click.option("--data-encoding", "-e", default="base64", show_default=True)
331
- @click.option("--compression", "-c", default="zstd", show_default=True)
413
+ @click.option(
414
+ "--key-encoding", default="base64", show_default=True, envvar="KEY_ENCODING"
415
+ )
416
+ @click.option(
417
+ "--data-encoding", "-e", default="base64", show_default=True, envvar="DATA_ENCODING"
418
+ )
419
+ @click.option(
420
+ "--compression", "-c", default="zstd", show_default=True, envvar="COMPRESSION"
421
+ )
332
422
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
333
- @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
423
+ @click.option(
424
+ "--verbose", "-v", is_flag=True, envvar="VERBOSE", help="Show verbose output."
425
+ )
334
426
  def decrypt_secret_cmd(
335
427
  key_file: Path,
336
428
  message_file: Path,
@@ -351,24 +443,33 @@ def decrypt_secret_cmd(
351
443
  unarchiver = UNARCHIVERS[compression]
352
444
 
353
445
  key = read_key_bytes(source=key_file, encoder=key_enc)
354
- data = stats = read_bytes(source=message_file, encoder=data_enc)
355
- data = data_enc.decode(data)
446
+ ciphertext = read_bytes(source=message_file, encoder=data_enc)
447
+ data = data_enc.decode(ciphertext)
356
448
  data = secret.decrypt(key=key, data=data)
357
- data = unarchiver(data)
449
+ plaintext = unarchiver(data)
450
+
451
+ write_output(target=output_file, data=plaintext)
358
452
 
359
- write_output(target=output_file, data=data)
360
453
  if verbose:
361
- print_stats(plaintext=data, ciphertext=stats)
454
+ print_stats(len(plaintext), len(ciphertext))
362
455
 
363
456
 
364
457
  @cli.command(aliases=["dp"]) # pyright: ignore[reportAny]
365
458
  @click.argument("password_file", type=in_path)
366
459
  @click.argument("message_file", type=in_path)
367
- @click.option("--kdf-profile", "-p", default="sensitive", show_default=True)
368
- @click.option("--data-encoding", "-e", default="base64", show_default=True)
369
- @click.option("--compression", "-c", default="zstd", show_default=True)
460
+ @click.option(
461
+ "--kdf-profile", "-p", default="sensitive", show_default=True, envvar="KDF_PROFILE"
462
+ )
463
+ @click.option(
464
+ "--data-encoding", "-e", default="base64", show_default=True, envvar="DATA_ENCODING"
465
+ )
466
+ @click.option(
467
+ "--compression", "-c", default="zstd", show_default=True, envvar="COMPRESSION"
468
+ )
370
469
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
371
- @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
470
+ @click.option(
471
+ "--verbose", "-v", is_flag=True, envvar="VERBOSE", help="Show verbose output."
472
+ )
372
473
  def decrypt_password_cmd(
373
474
  password_file: Path,
374
475
  message_file: Path,
@@ -392,14 +493,15 @@ def decrypt_password_cmd(
392
493
 
393
494
  pw = read_password_bytes(password_file)
394
495
  key = kdf(password=pw, profile=prof)
395
- data = stats = read_bytes(source=message_file, encoder=data_enc)
396
- data = data_enc.decode(data)
496
+ ciphertext = read_bytes(source=message_file, encoder=data_enc)
497
+ data = data_enc.decode(ciphertext)
397
498
  data = secret.decrypt(key=key, data=data)
398
- data = unarchiver(data)
499
+ plaintext = unarchiver(data)
500
+
501
+ write_output(target=output_file, data=plaintext)
399
502
 
400
- write_output(target=output_file, data=data)
401
503
  if verbose:
402
- print_stats(plaintext=data, ciphertext=stats)
504
+ print_stats(len(plaintext), len(ciphertext))
403
505
 
404
506
 
405
507
  @cli.command() # pyright: ignore[reportAny]
@@ -407,9 +509,12 @@ def decrypt_password_cmd(
407
509
  @click.argument("out_encoding")
408
510
  @click.argument("file", type=in_path)
409
511
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
410
- @click.option("--group-len", default=0, show_default=True)
411
- @click.option("--line-len", default=0, show_default=True)
412
- @click.option("--padding", default=0, show_default=True)
512
+ @click.option("--group-len", default=0, show_default=True, envvar="GROUP_LEN")
513
+ @click.option("--line-len", default=80, show_default=True, envvar="LINE_LEN")
514
+ @click.option("--padding", default=0, show_default=True, envvar="PADDING")
515
+ @click.option(
516
+ "--verbose", "-v", is_flag=True, envvar="VERBOSE", help="Show verbose output."
517
+ )
413
518
  def encode_cmd(
414
519
  in_encoding: str,
415
520
  out_encoding: str,
@@ -418,6 +523,7 @@ def encode_cmd(
418
523
  group_len: int,
419
524
  line_len: int,
420
525
  padding: int,
526
+ verbose: bool,
421
527
  ) -> None:
422
528
  """Encode File.
423
529
 
@@ -430,10 +536,17 @@ def encode_cmd(
430
536
  data = in_enc.decode(data)
431
537
  data = out_enc.encode(data)
432
538
 
433
- if not out_enc.is_binary:
434
- data = format_output(data, group_len, line_len, padding)
539
+ formatted, groups = format_output(
540
+ data=data,
541
+ encoder=out_enc,
542
+ group_len=group_len,
543
+ line_len=line_len,
544
+ padding=padding,
545
+ )
546
+ write_output(target=output_file, data=formatted)
435
547
 
436
- write_output(target=output_file, data=data)
548
+ if verbose:
549
+ click.echo(f"Groups: {groups}", err=True)
437
550
 
438
551
 
439
552
  if __name__ == "__main__":
rtty_soda/main.pyi CHANGED
@@ -2,7 +2,12 @@ from pathlib import Path
2
2
 
3
3
  def cli() -> None: ...
4
4
  def genkey_cmd(
5
- encoding: str, output_file: Path | None, group_len: int, line_len: int, padding: int
5
+ encoding: str,
6
+ output_file: Path | None,
7
+ group_len: int,
8
+ line_len: int,
9
+ padding: int,
10
+ verbose: bool,
6
11
  ) -> None: ...
7
12
  def pubkey_cmd(
8
13
  private_key_file: Path,
@@ -11,6 +16,7 @@ def pubkey_cmd(
11
16
  group_len: int,
12
17
  line_len: int,
13
18
  padding: int,
19
+ verbose: bool,
14
20
  ) -> None: ...
15
21
  def kdf_cmd(
16
22
  password_file: Path,
@@ -20,6 +26,7 @@ def kdf_cmd(
20
26
  group_len: int,
21
27
  line_len: int,
22
28
  padding: int,
29
+ verbose: bool,
23
30
  ) -> None: ...
24
31
  def encrypt_public_cmd(
25
32
  private_key_file: Path,
@@ -66,7 +73,6 @@ def decrypt_public_cmd(
66
73
  data_encoding: str,
67
74
  compression: str,
68
75
  output_file: Path | None,
69
- padding: int,
70
76
  verbose: bool,
71
77
  ) -> None: ...
72
78
  def decrypt_secret_cmd(
@@ -76,7 +82,6 @@ def decrypt_secret_cmd(
76
82
  data_encoding: str,
77
83
  compression: str,
78
84
  output_file: Path | None,
79
- padding: int,
80
85
  verbose: bool,
81
86
  ) -> None: ...
82
87
  def decrypt_password_cmd(
@@ -86,7 +91,6 @@ def decrypt_password_cmd(
86
91
  data_encoding: str,
87
92
  compression: str,
88
93
  output_file: Path | None,
89
- padding: int,
90
94
  verbose: bool,
91
95
  ) -> None: ...
92
96
  def encode_cmd(
@@ -97,4 +101,5 @@ def encode_cmd(
97
101
  group_len: int,
98
102
  line_len: int,
99
103
  padding: int,
104
+ verbose: bool,
100
105
  ) -> None: ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rtty-soda
3
- Version: 0.2.1
3
+ Version: 0.2.3
4
4
  Summary: A CLI tool for Unix-like environments to encrypt a RTTY session using NaCl
5
5
  Keywords: cli,encryption,libsodium,nacl,rtty
6
6
  Author: Theo Saveliev
@@ -57,8 +57,8 @@ A CLI tool for Unix-like environments to encrypt a RTTY session using NaCl.
57
57
  #### Docker
58
58
 
59
59
  ```
60
- % docker run -it --rm -h rtty-soda -v .:/app/host nett/rtty-soda:0.2.1
61
- % docker run -it --rm -h rtty-soda -v .:/app/host nett/rtty-soda:0.2.1-tools
60
+ % docker run -it --rm -h rtty-soda -v .:/app/host nett/rtty-soda:0.2.3
61
+ % docker run -it --rm -h rtty-soda -v .:/app/host nett/rtty-soda:0.2.3-tools
62
62
  ```
63
63
 
64
64
 
@@ -112,8 +112,9 @@ Options:
112
112
  -e, --encoding TEXT [default: base64]
113
113
  -o, --output-file FILE Write output to file.
114
114
  --group-len INTEGER [default: 0]
115
- --line-len INTEGER [default: 0]
115
+ --line-len INTEGER [default: 80]
116
116
  --padding INTEGER [default: 0]
117
+ -v, --verbose Show verbose output.
117
118
  -h, --help Show this message and exit.
118
119
  ```
119
120
 
@@ -128,11 +129,11 @@ transmit text messages in Morse code in a telegraphy system.
128
129
  The first telegraph key was invented by Alfred Vail, an associate of Samuel Morse.
129
130
  (c) Wikipedia
130
131
 
131
- % soda encrypt-public alice bob_pub message --line-len 80 | tee encrypted
132
- cCipniCmJVAb2mc3JLoDo/DAun7cMunWS5bMqtKRPc/e3d2vfRm8wnqTsYjOXVOCZRj78/GqcVweBV0
133
- mE43X7xO8B0OVyKKgqPAqnAJxwggTLPmWtKFrTwKi0utf7n6fIQuDaCths0qO6FF5rm0znc/3KYKP3D
134
- /WbgE/IBrTOAV6P+mLUnGlzO6U/HdtDCjk1ZB45EN0Q76dDzYav+bliCrVWiAUfZUCtEQ/6B4fi9Aqn
135
- KRDC4XSnd7nLs/ZkhL8hkM13xJ+1MBGbIvEjaY=
132
+ % soda encrypt-public alice bob_pub message --group-len 79 | tee encrypted
133
+ q+zCgyCfHdlSHrcuyM/Yfw1+ZvqNRXgY0O7gGrauPyQlsI0MdPXoVlkfyKZUtg6Jcqn47d4BGLMBITo
134
+ y3Wp9+9FvI1rolCd7JmyIxRIHHYWqxux+czh88aDdGjbDQ2pRNX68TU33PylBDw/H+VfYSZ6fyw1xdJ
135
+ 005pJeEXCzpOXljvXMgAElBIFJ/vsluunrRI9Sw6WcnrCsPYFxTFRZVOvsq6U8PJwnhnaDyLW0Z28Op
136
+ dS71gNH/7xA7P1LbFwxSD0jAjDqPZdLYkPzd94=
136
137
 
137
138
  % soda encrypt-public -h
138
139
  Usage: soda encrypt-public [OPTIONS] PRIVATE_KEY_FILE PUBLIC_KEY_FILE
@@ -150,7 +151,7 @@ Options:
150
151
  -c, --compression TEXT [default: zstd]
151
152
  -o, --output-file FILE Write output to file.
152
153
  --group-len INTEGER [default: 0]
153
- --line-len INTEGER [default: 0]
154
+ --line-len INTEGER [default: 80]
154
155
  --padding INTEGER [default: 0]
155
156
  -v, --verbose Show verbose output.
156
157
  -h, --help Show this message and exit.
@@ -164,24 +165,6 @@ A telegraph key is a specialized electrical switch used by a trained operator to
164
165
  transmit text messages in Morse code in a telegraphy system.
165
166
  The first telegraph key was invented by Alfred Vail, an associate of Samuel Morse.
166
167
  (c) Wikipedia
167
-
168
- % soda decrypt-public -h
169
- Usage: soda decrypt-public [OPTIONS] PRIVATE_KEY_FILE PUBLIC_KEY_FILE
170
- MESSAGE_FILE
171
-
172
- Decrypt Message (Public).
173
-
174
- Encoding: base26 | base31 | base36 | base64 | base94 | binary
175
-
176
- Compression: zstd | zlib | bz2 | lzma | raw
177
-
178
- Options:
179
- --key-encoding TEXT [default: base64]
180
- -e, --data-encoding TEXT [default: base64]
181
- -c, --compression TEXT [default: zstd]
182
- -o, --output-file FILE Write output to file.
183
- -v, --verbose Show verbose output.
184
- -h, --help Show this message and exit.
185
168
  ```
186
169
 
187
170
 
@@ -193,26 +176,6 @@ Alice and Bob share a key for symmetric encryption:
193
176
  % soda genkey > shared
194
177
  % soda encrypt-secret shared message -o encrypted
195
178
  % soda decrypt-secret shared encrypted -o message
196
-
197
- % soda encrypt-secret -h
198
- Usage: soda encrypt-secret [OPTIONS] KEY_FILE MESSAGE_FILE
199
-
200
- Encrypt Message (Secret).
201
-
202
- Encoding: base26 | base31 | base36 | base64 | base94 | binary
203
-
204
- Compression: zstd | zlib | bz2 | lzma | raw
205
-
206
- Options:
207
- --key-encoding TEXT [default: base64]
208
- -e, --data-encoding TEXT [default: base64]
209
- -c, --compression TEXT [default: zstd]
210
- -o, --output-file FILE Write output to file.
211
- --group-len INTEGER [default: 0]
212
- --line-len INTEGER [default: 0]
213
- --padding INTEGER [default: 0]
214
- -v, --verbose Show verbose output.
215
- -h, --help Show this message and exit.
216
179
  ```
217
180
 
218
181
  Another day, they share a password:
@@ -220,28 +183,6 @@ Another day, they share a password:
220
183
  ```
221
184
  % echo qwerty | soda encrypt-password - message -p interactive -o encrypted
222
185
  % echo qwerty | soda decrypt-password - encrypted -p interactive -o message
223
-
224
- % soda encrypt-password -h
225
- Usage: soda encrypt-password [OPTIONS] PASSWORD_FILE MESSAGE_FILE
226
-
227
- Encrypt Message (Password).
228
-
229
- KDF profile: interactive | moderate | sensitive
230
-
231
- Encoding: base26 | base31 | base36 | base64 | base94 | binary
232
-
233
- Compression: zstd | zlib | bz2 | lzma | raw
234
-
235
- Options:
236
- -p, --kdf-profile TEXT [default: sensitive]
237
- -e, --data-encoding TEXT [default: base64]
238
- -c, --compression TEXT [default: zstd]
239
- -o, --output-file FILE Write output to file.
240
- --group-len INTEGER [default: 0]
241
- --line-len INTEGER [default: 0]
242
- --padding INTEGER [default: 0]
243
- -v, --verbose Show verbose output.
244
- -h, --help Show this message and exit.
245
186
  ```
246
187
 
247
188
 
@@ -268,8 +209,9 @@ Options:
268
209
  -p, --profile TEXT [default: sensitive]
269
210
  -o, --output-file FILE Write output to file.
270
211
  --group-len INTEGER [default: 0]
271
- --line-len INTEGER [default: 0]
212
+ --line-len INTEGER [default: 80]
272
213
  --padding INTEGER [default: 0]
214
+ -v, --verbose Show verbose output.
273
215
  -h, --help Show this message and exit.
274
216
  ```
275
217
 
@@ -286,22 +228,27 @@ That works as follows:
286
228
  Plaintext: 239
287
229
  Ciphertext: 276
288
230
  Overhead: 1.155
231
+ Groups: 1
289
232
  % soda es shared message -c zlib -v > /dev/null
290
233
  Plaintext: 239
291
234
  Ciphertext: 280
292
235
  Overhead: 1.172
236
+ Groups: 1
293
237
  % soda es shared message -c bz2 -v > /dev/null
294
238
  Plaintext: 239
295
239
  Ciphertext: 340
296
240
  Overhead: 1.423
241
+ Groups: 1
297
242
  % soda es shared message -c lzma -v > /dev/null
298
243
  Plaintext: 239
299
244
  Ciphertext: 324
300
245
  Overhead: 1.356
246
+ Groups: 1
301
247
  % soda es shared message -c raw -v > /dev/null
302
248
  Plaintext: 239
303
249
  Ciphertext: 372
304
250
  Overhead: 1.556
251
+ Groups: 1
305
252
  ```
306
253
 
307
254
 
@@ -310,15 +257,59 @@ Overhead: 1.556
310
257
  The rtty-soda supports various encodings:
311
258
 
312
259
  ```
313
- % soda encrypt-public alice bob_pub message --data-encoding base36 --group-len 5 --line-len 80
314
- 9TPUZ T8OA3 PNC2Z XEH87 EPMCN NDQJJ GX0DE YW16D OJ2FC D3PCM B148K 6UZFN 9RQX7
315
- 8C83X 6O8WS MQ4CX 26C7H 35EK5 CVSIX IFSVN KPV6A TRV1F 573WI JFFGE I7N3Z Z4N6D
316
- FSSOB DJUBK PC2YW Z6RG0 SUD2N OIYH8 WHJMN YYSKQ EBEVJ ZT0M1 DYJ7E NJ25J FMXNE
317
- 7LHUQ N5UIH SK5O7 96LWM IZ7BA R8SIV 6G55R Q50L4 PJH5Z 2JQNX JZTPK BG140 AKXOB
318
- DKR4K POW9A HCQSQ JLSJ1 11AZY P8BM4 F3GUC SFX04 RMD0G 4V0PL RLRHN G8D8
260
+ % soda encrypt-public alice bob_pub message --data-encoding base36 --group-len 5 --verbose
261
+ 9URCN ARRN8 MSE7G G9980 37D8S 568QP 16AZW TOHAI KYP5W VAK7R VZ6YO GZ38A QOIP7
262
+ 60P2E GWWOG DSHDD EG2TZ 7PSZM 7FKBX 50TAD RHS2E VM063 N297Y 753BP TLUX0 9K8BD
263
+ DZF8O 7TPUG MJV4R T2C92 HU1G8 KGJCN URU1F 9COP9 EFLZO BSL2V 171DS 2HKPE JY2GY
264
+ V86IT T0HBR 9B08H M9R2V IEM7A R91IF UWQYM ZV4JN 7YU3K ILPJY E8OMA NWQC5 Q6BG7
265
+ PXM4I 9UU9E J9IRU HSZ41 RPZQG XTDC6 E5NMS B4HBQ 7QRI2 RRUYH HSHGQ 7USN
266
+ Plaintext: 239
267
+ Ciphertext: 319
268
+ Overhead: 1.335
269
+ Groups: 64
270
+ ```
271
+
272
+
273
+ ## Environment variables
274
+
275
+ Common options can be set in the environment variables:
276
+
277
+ ```
278
+ % cat .env
279
+ KEY_ENCODING=base26
280
+ DATA_ENCODING=base26
281
+ COMPRESSION=bz2
282
+ KDF_PROFILE=moderate
283
+ VERBOSE=1
284
+ GROUP_LEN=5
285
+ LINE_LEN=80
286
+ PADDING=1
287
+
288
+ % set -a
289
+ % source .env
319
290
  ```
320
291
 
321
292
 
293
+ ## Alternative usage
294
+
295
+ - Password source
296
+ ```
297
+ % echo 'A line from a book or a poem' | soda kdf - -e base94
298
+ wN/K.@3Q#]Czn4kk3(negX=R|*xvvPQmk'XW$-s
299
+ ```
300
+
301
+ - WireGuard keyer
302
+ ```
303
+ % echo 'A line from a book or a poem' | soda kdf - -o privkey
304
+ % cat privkey
305
+ thyA4dlQgg93+rQj/evBbBymw82GTwQCh3RJ0I6GOsY=
306
+ % soda pubkey privkey
307
+ ruIUMqbUtyqRVSIBLSGI7AOruE2DLWgTe9o+h7Yktkw=
308
+ % cat privkey | wg pubkey
309
+ ruIUMqbUtyqRVSIBLSGI7AOruE2DLWgTe9o+h7Yktkw=
310
+ ```
311
+
312
+
322
313
  ## Compatibility
323
314
 
324
315
  During the initial development (versions prior to 1.0.0),
@@ -1,6 +1,6 @@
1
1
  rtty_soda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  rtty_soda/archivers.py,sha256=b-qZ6-MAY1rm1Jsosi2XEfjNjkU7acAedHmnSzthf-A,1343
3
- rtty_soda/cli_io.py,sha256=01d0IWv2lpOBB13TKB0ZbiLpSXep9J53lXiOsy9HNEM,3162
3
+ rtty_soda/cli_io.py,sha256=mkCYMp_Cm9pKvvS7OE2KSeXzRVjoHfTlfqVGjyCnCyY,3040
4
4
  rtty_soda/cryptography/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  rtty_soda/cryptography/kdf.py,sha256=HymfTiK7BD7lhZu0OdtFW_i-v0r7e8XedT8_Q84ClJc,1529
6
6
  rtty_soda/cryptography/public.py,sha256=6gwsT4ilaMDHwtdYPOEYlX8IfwHPew8lMIbxRva1mLs,612
@@ -14,10 +14,10 @@ rtty_soda/encoders/base94_encoder.py,sha256=Xbt0chbeAIM9_nRHVhRMVfMBUKS9q1gNSpg2
14
14
  rtty_soda/encoders/encoder.py,sha256=trHunjg0uNEQrQWTpRMY5nQEx5_jBrcvfUAcGIKpgms,220
15
15
  rtty_soda/encoders/functions.py,sha256=JxtgbZg3kdbFqAhjm59QwJS6zEXYsR1m02k7cg_rFI4,1385
16
16
  rtty_soda/encoders/raw_encoder.py,sha256=eJnUSsxf3jichdQ5LqwvBZAX7-qk67p5FMlfKOOGHp8,259
17
- rtty_soda/main.py,sha256=QPVvnNkZgMHZQQ7mQUOiHLDuVA1WFfEZVJqgZxp_6hs,14679
18
- rtty_soda/main.pyi,sha256=1_ahHQ89q7lC2cQ0Vgk4QXwsP0G9c10XYGvrVsO1U0s,2203
17
+ rtty_soda/main.py,sha256=OEaefD5VxbL6P4NWWtNb9Am9wJegkesg29xzjYy1oxU,17319
18
+ rtty_soda/main.pyi,sha256=SoTM1GXACRafCtwwLOI1X9YhvEo3DPoaPtKSgWacSS0,2242
19
19
  rtty_soda/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- rtty_soda-0.2.1.dist-info/WHEEL,sha256=M6du7VZflc4UPsGphmOXHANdgk8zessdJG0DBUuoA-U,78
21
- rtty_soda-0.2.1.dist-info/entry_points.txt,sha256=tFROKkaDoE_p5tM2ko7MoAjWBFurchcw3j-MdObxBU0,45
22
- rtty_soda-0.2.1.dist-info/METADATA,sha256=OXeQ9VdCEzSNtvDtY4dJNVrCR4jPxEVPl88ExekIxbM,9616
23
- rtty_soda-0.2.1.dist-info/RECORD,,
20
+ rtty_soda-0.2.3.dist-info/WHEEL,sha256=M6du7VZflc4UPsGphmOXHANdgk8zessdJG0DBUuoA-U,78
21
+ rtty_soda-0.2.3.dist-info/entry_points.txt,sha256=tFROKkaDoE_p5tM2ko7MoAjWBFurchcw3j-MdObxBU0,45
22
+ rtty_soda-0.2.3.dist-info/METADATA,sha256=BZR-y-ilDaepE0j8RuckR-IHCK1nPeMUCq96ySPxnp0,8603
23
+ rtty_soda-0.2.3.dist-info/RECORD,,