rtty-soda 0.2.0__py3-none-any.whl → 0.2.2__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
@@ -11,6 +11,7 @@ import click
11
11
  from rtty_soda.encoders import Encoder, decode_bytes, encode_str
12
12
 
13
13
  __all__ = [
14
+ "format_output",
14
15
  "pad_newlines",
15
16
  "print_stats",
16
17
  "read_bytes",
@@ -40,15 +41,15 @@ def read_encoded_stripped(source: Path) -> bytes:
40
41
  return encode_str(data)
41
42
 
42
43
 
43
- def read_bytes(source: Path, is_binary: bool) -> bytes:
44
- if is_binary:
44
+ def read_bytes(source: Path, encoder: Encoder) -> bytes:
45
+ if encoder.is_binary:
45
46
  return source.read_bytes()
46
47
 
47
48
  return read_encoded_stripped(source)
48
49
 
49
50
 
50
- def read_key_bytes(source: Path, is_binary: bool, encoder: Encoder) -> bytes:
51
- key = read_bytes(source, is_binary)
51
+ def read_key_bytes(source: Path, encoder: Encoder) -> bytes:
52
+ key = read_bytes(source, encoder)
52
53
  return encoder.decode(key)
53
54
 
54
55
 
@@ -63,48 +64,36 @@ def write_bytes_atomic(target: Path, data: bytes) -> None:
63
64
  temp_path.replace(target)
64
65
 
65
66
 
66
- def split_groups(data: str, group_len: int, line_len: int) -> str:
67
- step = group_len if group_len > 0 else line_len - 1
68
- groups = (data[i : i + step] for i in range(0, len(data), step))
69
- result: list[str] = []
70
- line: list[str] = []
71
- i = 0
72
- gpl = line_len // (step + 1)
73
- for group in groups:
74
- line.append(group)
75
- i += 1
76
- if i == gpl:
77
- result.append(" ".join(line))
78
- i = 0
79
- line = []
80
-
81
- if line:
82
- result.append(" ".join(line))
83
-
84
- return "\n".join(result)
85
-
86
-
87
- def pad_newlines(data: bytes, count: int) -> bytes:
88
- padding = b"\n" * count
89
- return padding + data + padding
90
-
91
-
92
- def write_output(
93
- target: Path | None,
94
- data: bytes,
95
- is_binary: bool,
96
- group_len: int,
97
- line_len: int,
98
- padding: int,
99
- ) -> None:
100
- if not is_binary and (group_len > 0 or line_len > 0):
101
- text = decode_bytes(data)
102
- text = split_groups(text, group_len, line_len)
103
- data = encode_str(text)
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)
72
+
73
+
74
+ def pad_newlines(data: str, count: int) -> str:
75
+ padding = "\n" * count
76
+ return padding + data.strip() + "\n" + padding
77
+
78
+
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
+
86
+ text = decode_bytes(data)
87
+ if 0 < group_len < line_len:
88
+ text, groups = split_groups(text, group_len, line_len)
104
89
 
105
90
  if padding > 0:
106
- data = pad_newlines(data, padding)
91
+ text = pad_newlines(text, padding)
92
+
93
+ return encode_str(text), groups
94
+
107
95
 
96
+ def write_output(target: Path | None, data: bytes) -> None:
108
97
  if target is None or target.stem == "-":
109
98
  add_nl = not data.endswith(b"\n")
110
99
  click.echo(data, nl=add_nl)
@@ -1,6 +1,6 @@
1
1
  import string
2
+ from typing import ClassVar
2
3
 
3
- from .encoder import Encoder
4
4
  from .functions import base_to_bytes, bytes_to_base, decode_bytes, encode_str
5
5
 
6
6
  __all__ = ["ALPHABET", "Base26Encoder"]
@@ -8,7 +8,9 @@ __all__ = ["ALPHABET", "Base26Encoder"]
8
8
  ALPHABET = string.ascii_uppercase
9
9
 
10
10
 
11
- class Base26Encoder(Encoder):
11
+ class Base26Encoder:
12
+ is_binary: ClassVar = False
13
+
12
14
  @staticmethod
13
15
  def encode(data: bytes) -> bytes:
14
16
  return encode_str(bytes_to_base(data, ALPHABET))
@@ -1,4 +1,5 @@
1
- from .encoder import Encoder
1
+ from typing import ClassVar
2
+
2
3
  from .functions import base_to_bytes, bytes_to_base, decode_bytes, encode_str
3
4
 
4
5
  __all__ = ["ALPHABET", "Base31Encoder"]
@@ -6,7 +7,9 @@ __all__ = ["ALPHABET", "Base31Encoder"]
6
7
  ALPHABET = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЭЮЯ"
7
8
 
8
9
 
9
- class Base31Encoder(Encoder):
10
+ class Base31Encoder:
11
+ is_binary: ClassVar = False
12
+
10
13
  @staticmethod
11
14
  def encode(data: bytes) -> bytes:
12
15
  return encode_str(bytes_to_base(data, ALPHABET))
@@ -1,6 +1,6 @@
1
1
  import string
2
+ from typing import ClassVar
2
3
 
3
- from .encoder import Encoder
4
4
  from .functions import base_to_bytes, bytes_to_base, decode_bytes, encode_str
5
5
 
6
6
  __all__ = ["ALPHABET", "Base36Encoder"]
@@ -8,7 +8,9 @@ __all__ = ["ALPHABET", "Base36Encoder"]
8
8
  ALPHABET = string.digits + string.ascii_uppercase
9
9
 
10
10
 
11
- class Base36Encoder(Encoder):
11
+ class Base36Encoder:
12
+ is_binary: ClassVar = False
13
+
12
14
  @staticmethod
13
15
  def encode(data: bytes) -> bytes:
14
16
  return encode_str(bytes_to_base(data, ALPHABET))
@@ -1,11 +1,12 @@
1
1
  import base64
2
-
3
- from .encoder import Encoder
2
+ from typing import ClassVar
4
3
 
5
4
  __all__ = ["Base64Encoder"]
6
5
 
7
6
 
8
- class Base64Encoder(Encoder):
7
+ class Base64Encoder:
8
+ is_binary: ClassVar = False
9
+
9
10
  @staticmethod
10
11
  def encode(data: bytes) -> bytes:
11
12
  return base64.b64encode(data)
@@ -1,4 +1,5 @@
1
- from .encoder import Encoder
1
+ from typing import ClassVar
2
+
2
3
  from .functions import base_to_bytes, bytes_to_base, decode_bytes, encode_str
3
4
 
4
5
  __all__ = ["ALPHABET", "Base94Encoder"]
@@ -6,7 +7,9 @@ __all__ = ["ALPHABET", "Base94Encoder"]
6
7
  ALPHABET = "".join([chr(i) for i in range(33, 127)])
7
8
 
8
9
 
9
- class Base94Encoder(Encoder):
10
+ class Base94Encoder:
11
+ is_binary: ClassVar = False
12
+
10
13
  @staticmethod
11
14
  def encode(data: bytes) -> bytes:
12
15
  return encode_str(bytes_to_base(data, ALPHABET))
@@ -4,6 +4,8 @@ __all__ = ["Encoder"]
4
4
 
5
5
 
6
6
  class Encoder(Protocol):
7
+ is_binary: bool
8
+
7
9
  @staticmethod
8
10
  def encode(data: bytes) -> bytes: ...
9
11
 
@@ -1,9 +1,11 @@
1
- from .encoder import Encoder
1
+ from typing import ClassVar
2
2
 
3
3
  __all__ = ["RawEncoder"]
4
4
 
5
5
 
6
- class RawEncoder(Encoder):
6
+ class RawEncoder:
7
+ is_binary: ClassVar = True
8
+
7
9
  @staticmethod
8
10
  def encode(data: bytes) -> bytes:
9
11
  return data
rtty_soda/main.py CHANGED
@@ -6,6 +6,7 @@ from nacl.public import PrivateKey, PublicKey
6
6
 
7
7
  from rtty_soda.archivers import ARCHIVERS, UNARCHIVERS
8
8
  from rtty_soda.cli_io import (
9
+ format_output,
9
10
  print_stats,
10
11
  read_bytes,
11
12
  read_key_bytes,
@@ -42,29 +43,33 @@ def cli() -> None:
42
43
  @click.option("--encoding", "-e", default="base64", show_default=True)
43
44
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
44
45
  @click.option("--group-len", default=0, show_default=True)
45
- @click.option("--line-len", default=0, show_default=True)
46
+ @click.option("--line-len", default=80, show_default=True)
46
47
  @click.option("--padding", default=0, show_default=True)
48
+ @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
47
49
  def genkey_cmd(
48
- encoding: str, output_file: Path | None, group_len: int, line_len: int, padding: int
50
+ encoding: str,
51
+ output_file: Path | None,
52
+ group_len: int,
53
+ line_len: int,
54
+ padding: int,
55
+ verbose: bool,
49
56
  ) -> None:
50
57
  """Generate Private Key.
51
58
 
52
59
  Encoding: base26 | base31 | base36 | base64 | base94 | binary
53
60
  """
54
61
  enc = ENCODERS[encoding]
55
- is_bin = encoding == "binary"
56
62
 
57
63
  key = bytes(PrivateKey.generate())
58
64
  key = enc.encode(key)
59
65
 
60
- write_output(
61
- target=output_file,
62
- data=key,
63
- is_binary=is_bin,
64
- group_len=group_len,
65
- line_len=line_len,
66
- padding=padding,
66
+ key, groups = format_output(
67
+ data=key, encoder=enc, group_len=group_len, line_len=line_len, padding=padding
67
68
  )
69
+ write_output(target=output_file, data=key)
70
+
71
+ if verbose:
72
+ click.echo(f"Groups: {groups}", err=True)
68
73
 
69
74
 
70
75
  @cli.command() # pyright: ignore[reportAny]
@@ -72,8 +77,9 @@ def genkey_cmd(
72
77
  @click.option("--encoding", "-e", default="base64", show_default=True)
73
78
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
74
79
  @click.option("--group-len", default=0, show_default=True)
75
- @click.option("--line-len", default=0, show_default=True)
80
+ @click.option("--line-len", default=80, show_default=True)
76
81
  @click.option("--padding", default=0, show_default=True)
82
+ @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
77
83
  def pubkey_cmd(
78
84
  private_key_file: Path,
79
85
  encoding: str,
@@ -81,27 +87,26 @@ def pubkey_cmd(
81
87
  group_len: int,
82
88
  line_len: int,
83
89
  padding: int,
90
+ verbose: bool,
84
91
  ) -> None:
85
92
  """Get Public Key.
86
93
 
87
94
  Encoding: base26 | base31 | base36 | base64 | base94 | binary
88
95
  """
89
96
  enc = ENCODERS[encoding]
90
- is_bin = encoding == "binary"
91
97
 
92
- priv = read_key_bytes(source=private_key_file, is_binary=is_bin, encoder=enc)
98
+ priv = read_key_bytes(source=private_key_file, encoder=enc)
93
99
  priv = PrivateKey(private_key=priv)
94
100
  pub = bytes(priv.public_key)
95
101
  pub = enc.encode(pub)
96
102
 
97
- write_output(
98
- target=output_file,
99
- data=pub,
100
- is_binary=is_bin,
101
- group_len=group_len,
102
- line_len=line_len,
103
- padding=padding,
103
+ pub, groups = format_output(
104
+ data=pub, encoder=enc, group_len=group_len, line_len=line_len, padding=padding
104
105
  )
106
+ write_output(target=output_file, data=pub)
107
+
108
+ if verbose:
109
+ click.echo(f"Groups: {groups}", err=True)
105
110
 
106
111
 
107
112
  @cli.command() # pyright: ignore[reportAny]
@@ -110,8 +115,9 @@ def pubkey_cmd(
110
115
  @click.option("--profile", "-p", default="sensitive", show_default=True)
111
116
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
112
117
  @click.option("--group-len", default=0, show_default=True)
113
- @click.option("--line-len", default=0, show_default=True)
118
+ @click.option("--line-len", default=80, show_default=True)
114
119
  @click.option("--padding", default=0, show_default=True)
120
+ @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
115
121
  def kdf_cmd(
116
122
  password_file: Path,
117
123
  encoding: str,
@@ -120,6 +126,7 @@ def kdf_cmd(
120
126
  group_len: int,
121
127
  line_len: int,
122
128
  padding: int,
129
+ verbose: bool,
123
130
  ) -> None:
124
131
  """Key Derivation Function.
125
132
 
@@ -129,20 +136,18 @@ def kdf_cmd(
129
136
  """
130
137
  enc = ENCODERS[encoding]
131
138
  prof = KDF_PROFILES[profile]
132
- is_bin = encoding == "binary"
133
139
 
134
140
  pw = read_password_bytes(password_file)
135
141
  key = kdf(password=pw, profile=prof)
136
142
  key = enc.encode(key)
137
143
 
138
- write_output(
139
- target=output_file,
140
- data=key,
141
- is_binary=is_bin,
142
- group_len=group_len,
143
- line_len=line_len,
144
- padding=padding,
144
+ key, groups = format_output(
145
+ data=key, encoder=enc, group_len=group_len, line_len=line_len, padding=padding
145
146
  )
147
+ write_output(target=output_file, data=key)
148
+
149
+ if verbose:
150
+ click.echo(f"Groups: {groups}", err=True)
146
151
 
147
152
 
148
153
  @cli.command(aliases=["e"]) # pyright: ignore[reportAny]
@@ -154,7 +159,7 @@ def kdf_cmd(
154
159
  @click.option("--compression", "-c", default="zstd", show_default=True)
155
160
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
156
161
  @click.option("--group-len", default=0, show_default=True)
157
- @click.option("--line-len", default=0, show_default=True)
162
+ @click.option("--line-len", default=80, show_default=True)
158
163
  @click.option("--padding", default=0, show_default=True)
159
164
  @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
160
165
  def encrypt_public_cmd(
@@ -179,30 +184,28 @@ def encrypt_public_cmd(
179
184
  key_enc = ENCODERS[key_encoding]
180
185
  data_enc = ENCODERS[data_encoding]
181
186
  archiver = ARCHIVERS[compression]
182
- is_bin_key = key_encoding == "binary"
183
- is_bin_data = data_encoding == "binary"
184
187
 
185
- priv = read_key_bytes(
186
- source=private_key_file, is_binary=is_bin_key, encoder=key_enc
187
- )
188
+ priv = read_key_bytes(source=private_key_file, encoder=key_enc)
188
189
  priv = PrivateKey(private_key=priv)
189
- pub = read_key_bytes(source=public_key_file, is_binary=is_bin_key, encoder=key_enc)
190
+ pub = read_key_bytes(source=public_key_file, encoder=key_enc)
190
191
  pub = PublicKey(public_key=pub)
191
192
  data = stats = message_file.read_bytes()
192
193
  data = archiver(data)
193
194
  data = public.encrypt(private=priv, public=pub, data=data)
194
195
  data = data_enc.encode(data)
195
196
 
196
- write_output(
197
- target=output_file,
197
+ data, groups = format_output(
198
198
  data=data,
199
- is_binary=is_bin_data,
199
+ encoder=data_enc,
200
200
  group_len=group_len,
201
201
  line_len=line_len,
202
202
  padding=padding,
203
203
  )
204
+ write_output(target=output_file, data=data)
205
+
204
206
  if verbose:
205
207
  print_stats(plaintext=stats, ciphertext=data)
208
+ click.echo(f"Groups: {groups}", err=True)
206
209
 
207
210
 
208
211
  @cli.command(aliases=["es"]) # pyright: ignore[reportAny]
@@ -213,7 +216,7 @@ def encrypt_public_cmd(
213
216
  @click.option("--compression", "-c", default="zstd", show_default=True)
214
217
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
215
218
  @click.option("--group-len", default=0, show_default=True)
216
- @click.option("--line-len", default=0, show_default=True)
219
+ @click.option("--line-len", default=80, show_default=True)
217
220
  @click.option("--padding", default=0, show_default=True)
218
221
  @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
219
222
  def encrypt_secret_cmd(
@@ -237,25 +240,25 @@ def encrypt_secret_cmd(
237
240
  key_enc = ENCODERS[key_encoding]
238
241
  data_enc = ENCODERS[data_encoding]
239
242
  archiver = ARCHIVERS[compression]
240
- is_bin_key = key_encoding == "binary"
241
- is_bin_data = data_encoding == "binary"
242
243
 
243
- key = read_key_bytes(source=key_file, is_binary=is_bin_key, encoder=key_enc)
244
+ key = read_key_bytes(source=key_file, encoder=key_enc)
244
245
  data = stats = message_file.read_bytes()
245
246
  data = archiver(data)
246
247
  data = secret.encrypt(key=key, data=data)
247
248
  data = data_enc.encode(data)
248
249
 
249
- write_output(
250
- target=output_file,
250
+ data, groups = format_output(
251
251
  data=data,
252
- is_binary=is_bin_data,
252
+ encoder=data_enc,
253
253
  group_len=group_len,
254
254
  line_len=line_len,
255
255
  padding=padding,
256
256
  )
257
+ write_output(target=output_file, data=data)
258
+
257
259
  if verbose:
258
260
  print_stats(plaintext=stats, ciphertext=data)
261
+ click.echo(f"Groups: {groups}", err=True)
259
262
 
260
263
 
261
264
  @cli.command(aliases=["ep"]) # pyright: ignore[reportAny]
@@ -266,7 +269,7 @@ def encrypt_secret_cmd(
266
269
  @click.option("--compression", "-c", default="zstd", show_default=True)
267
270
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
268
271
  @click.option("--group-len", default=0, show_default=True)
269
- @click.option("--line-len", default=0, show_default=True)
272
+ @click.option("--line-len", default=80, show_default=True)
270
273
  @click.option("--padding", default=0, show_default=True)
271
274
  @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
272
275
  def encrypt_password_cmd(
@@ -292,7 +295,6 @@ def encrypt_password_cmd(
292
295
  prof = KDF_PROFILES[kdf_profile]
293
296
  data_enc = ENCODERS[data_encoding]
294
297
  archiver = ARCHIVERS[compression]
295
- is_bin_data = data_encoding == "binary"
296
298
 
297
299
  pw = read_password_bytes(password_file)
298
300
  key = kdf(password=pw, profile=prof)
@@ -301,16 +303,18 @@ def encrypt_password_cmd(
301
303
  data = secret.encrypt(key=key, data=data)
302
304
  data = data_enc.encode(data)
303
305
 
304
- write_output(
305
- target=output_file,
306
+ data, groups = format_output(
306
307
  data=data,
307
- is_binary=is_bin_data,
308
+ encoder=data_enc,
308
309
  group_len=group_len,
309
310
  line_len=line_len,
310
311
  padding=padding,
311
312
  )
313
+ write_output(target=output_file, data=data)
314
+
312
315
  if verbose:
313
316
  print_stats(plaintext=stats, ciphertext=data)
317
+ click.echo(f"Groups: {groups}", err=True)
314
318
 
315
319
 
316
320
  @cli.command(aliases=["d"]) # pyright: ignore[reportAny]
@@ -321,7 +325,6 @@ def encrypt_password_cmd(
321
325
  @click.option("--data-encoding", "-e", default="base64", show_default=True)
322
326
  @click.option("--compression", "-c", default="zstd", show_default=True)
323
327
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
324
- @click.option("--padding", default=0, show_default=True)
325
328
  @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
326
329
  def decrypt_public_cmd(
327
330
  private_key_file: Path,
@@ -331,7 +334,6 @@ def decrypt_public_cmd(
331
334
  data_encoding: str,
332
335
  compression: str,
333
336
  output_file: Path | None,
334
- padding: int,
335
337
  verbose: bool,
336
338
  ) -> None:
337
339
  """Decrypt Message (Public).
@@ -343,28 +345,18 @@ def decrypt_public_cmd(
343
345
  key_enc = ENCODERS[key_encoding]
344
346
  data_enc = ENCODERS[data_encoding]
345
347
  unarchiver = UNARCHIVERS[compression]
346
- is_bin_key = key_encoding == "binary"
347
- is_bin_data = data_encoding == "binary"
348
348
 
349
- priv = read_key_bytes(
350
- source=private_key_file, is_binary=is_bin_key, encoder=key_enc
351
- )
349
+ priv = read_key_bytes(source=private_key_file, encoder=key_enc)
352
350
  priv = PrivateKey(private_key=priv)
353
- pub = read_key_bytes(source=public_key_file, is_binary=is_bin_key, encoder=key_enc)
351
+ pub = read_key_bytes(source=public_key_file, encoder=key_enc)
354
352
  pub = PublicKey(public_key=pub)
355
- data = stats = read_bytes(source=message_file, is_binary=is_bin_data)
353
+ data = stats = read_bytes(source=message_file, encoder=data_enc)
356
354
  data = data_enc.decode(data)
357
355
  data = public.decrypt(private=priv, public=pub, data=data)
358
356
  data = unarchiver(data)
359
357
 
360
- write_output(
361
- target=output_file,
362
- data=data,
363
- is_binary=True,
364
- group_len=0,
365
- line_len=0,
366
- padding=padding,
367
- )
358
+ write_output(target=output_file, data=data)
359
+
368
360
  if verbose:
369
361
  print_stats(plaintext=data, ciphertext=stats)
370
362
 
@@ -376,7 +368,6 @@ def decrypt_public_cmd(
376
368
  @click.option("--data-encoding", "-e", default="base64", show_default=True)
377
369
  @click.option("--compression", "-c", default="zstd", show_default=True)
378
370
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
379
- @click.option("--padding", default=0, show_default=True)
380
371
  @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
381
372
  def decrypt_secret_cmd(
382
373
  key_file: Path,
@@ -385,7 +376,6 @@ def decrypt_secret_cmd(
385
376
  data_encoding: str,
386
377
  compression: str,
387
378
  output_file: Path | None,
388
- padding: int,
389
379
  verbose: bool,
390
380
  ) -> None:
391
381
  """Decrypt Message (Secret).
@@ -397,23 +387,15 @@ def decrypt_secret_cmd(
397
387
  key_enc = ENCODERS[key_encoding]
398
388
  data_enc = ENCODERS[data_encoding]
399
389
  unarchiver = UNARCHIVERS[compression]
400
- is_bin_key = key_encoding == "binary"
401
- is_bin_data = data_encoding == "binary"
402
390
 
403
- key = read_key_bytes(source=key_file, is_binary=is_bin_key, encoder=key_enc)
404
- data = stats = read_bytes(source=message_file, is_binary=is_bin_data)
391
+ key = read_key_bytes(source=key_file, encoder=key_enc)
392
+ data = stats = read_bytes(source=message_file, encoder=data_enc)
405
393
  data = data_enc.decode(data)
406
394
  data = secret.decrypt(key=key, data=data)
407
395
  data = unarchiver(data)
408
396
 
409
- write_output(
410
- target=output_file,
411
- data=data,
412
- is_binary=True,
413
- group_len=0,
414
- line_len=0,
415
- padding=padding,
416
- )
397
+ write_output(target=output_file, data=data)
398
+
417
399
  if verbose:
418
400
  print_stats(plaintext=data, ciphertext=stats)
419
401
 
@@ -425,7 +407,6 @@ def decrypt_secret_cmd(
425
407
  @click.option("--data-encoding", "-e", default="base64", show_default=True)
426
408
  @click.option("--compression", "-c", default="zstd", show_default=True)
427
409
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
428
- @click.option("--padding", default=0, show_default=True)
429
410
  @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
430
411
  def decrypt_password_cmd(
431
412
  password_file: Path,
@@ -434,7 +415,6 @@ def decrypt_password_cmd(
434
415
  data_encoding: str,
435
416
  compression: str,
436
417
  output_file: Path | None,
437
- padding: int,
438
418
  verbose: bool,
439
419
  ) -> None:
440
420
  """Decrypt Message (Password).
@@ -448,23 +428,16 @@ def decrypt_password_cmd(
448
428
  prof = KDF_PROFILES[kdf_profile]
449
429
  data_enc = ENCODERS[data_encoding]
450
430
  unarchiver = UNARCHIVERS[compression]
451
- is_bin_data = data_encoding == "binary"
452
431
 
453
432
  pw = read_password_bytes(password_file)
454
433
  key = kdf(password=pw, profile=prof)
455
- data = stats = read_bytes(source=message_file, is_binary=is_bin_data)
434
+ data = stats = read_bytes(source=message_file, encoder=data_enc)
456
435
  data = data_enc.decode(data)
457
436
  data = secret.decrypt(key=key, data=data)
458
437
  data = unarchiver(data)
459
438
 
460
- write_output(
461
- target=output_file,
462
- data=data,
463
- is_binary=True,
464
- group_len=0,
465
- line_len=0,
466
- padding=padding,
467
- )
439
+ write_output(target=output_file, data=data)
440
+
468
441
  if verbose:
469
442
  print_stats(plaintext=data, ciphertext=stats)
470
443
 
@@ -475,8 +448,9 @@ def decrypt_password_cmd(
475
448
  @click.argument("file", type=in_path)
476
449
  @click.option("--output-file", "-o", type=out_path, help="Write output to file.")
477
450
  @click.option("--group-len", default=0, show_default=True)
478
- @click.option("--line-len", default=0, show_default=True)
451
+ @click.option("--line-len", default=80, show_default=True)
479
452
  @click.option("--padding", default=0, show_default=True)
453
+ @click.option("--verbose", "-v", is_flag=True, help="Show verbose output.")
480
454
  def encode_cmd(
481
455
  in_encoding: str,
482
456
  out_encoding: str,
@@ -485,6 +459,7 @@ def encode_cmd(
485
459
  group_len: int,
486
460
  line_len: int,
487
461
  padding: int,
462
+ verbose: bool,
488
463
  ) -> None:
489
464
  """Encode File.
490
465
 
@@ -492,21 +467,22 @@ def encode_cmd(
492
467
  """
493
468
  in_enc = ENCODERS[in_encoding]
494
469
  out_enc = ENCODERS[out_encoding]
495
- in_bin = in_encoding == "binary"
496
- out_bin = out_encoding == "binary"
497
470
 
498
- data = read_bytes(source=file, is_binary=in_bin)
471
+ data = read_bytes(source=file, encoder=in_enc)
499
472
  data = in_enc.decode(data)
500
473
  data = out_enc.encode(data)
501
474
 
502
- write_output(
503
- target=output_file,
475
+ data, groups = format_output(
504
476
  data=data,
505
- is_binary=out_bin,
477
+ encoder=out_enc,
506
478
  group_len=group_len,
507
479
  line_len=line_len,
508
480
  padding=padding,
509
481
  )
482
+ write_output(target=output_file, data=data)
483
+
484
+ if verbose:
485
+ click.echo(f"Groups: {groups}", err=True)
510
486
 
511
487
 
512
488
  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.0
3
+ Version: 0.2.2
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.0
61
- % docker run -it --rm -h rtty-soda -v .:/app/host nett/rtty-soda:0.2.0-tools
60
+ % docker run -it --rm -h rtty-soda -v .:/app/host nett/rtty-soda:0.2.2
61
+ % docker run -it --rm -h rtty-soda -v .:/app/host nett/rtty-soda:0.2.2-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.
@@ -180,7 +181,6 @@ Options:
180
181
  -e, --data-encoding TEXT [default: base64]
181
182
  -c, --compression TEXT [default: zstd]
182
183
  -o, --output-file FILE Write output to file.
183
- --padding INTEGER [default: 0]
184
184
  -v, --verbose Show verbose output.
185
185
  -h, --help Show this message and exit.
186
186
  ```
@@ -210,7 +210,7 @@ Options:
210
210
  -c, --compression TEXT [default: zstd]
211
211
  -o, --output-file FILE Write output to file.
212
212
  --group-len INTEGER [default: 0]
213
- --line-len INTEGER [default: 0]
213
+ --line-len INTEGER [default: 80]
214
214
  --padding INTEGER [default: 0]
215
215
  -v, --verbose Show verbose output.
216
216
  -h, --help Show this message and exit.
@@ -239,7 +239,7 @@ Options:
239
239
  -c, --compression TEXT [default: zstd]
240
240
  -o, --output-file FILE Write output to file.
241
241
  --group-len INTEGER [default: 0]
242
- --line-len INTEGER [default: 0]
242
+ --line-len INTEGER [default: 80]
243
243
  --padding INTEGER [default: 0]
244
244
  -v, --verbose Show verbose output.
245
245
  -h, --help Show this message and exit.
@@ -269,8 +269,9 @@ Options:
269
269
  -p, --profile TEXT [default: sensitive]
270
270
  -o, --output-file FILE Write output to file.
271
271
  --group-len INTEGER [default: 0]
272
- --line-len INTEGER [default: 0]
272
+ --line-len INTEGER [default: 80]
273
273
  --padding INTEGER [default: 0]
274
+ -v, --verbose Show verbose output.
274
275
  -h, --help Show this message and exit.
275
276
  ```
276
277
 
@@ -287,22 +288,27 @@ That works as follows:
287
288
  Plaintext: 239
288
289
  Ciphertext: 276
289
290
  Overhead: 1.155
291
+ Groups: 1
290
292
  % soda es shared message -c zlib -v > /dev/null
291
293
  Plaintext: 239
292
294
  Ciphertext: 280
293
295
  Overhead: 1.172
296
+ Groups: 1
294
297
  % soda es shared message -c bz2 -v > /dev/null
295
298
  Plaintext: 239
296
299
  Ciphertext: 340
297
300
  Overhead: 1.423
301
+ Groups: 1
298
302
  % soda es shared message -c lzma -v > /dev/null
299
303
  Plaintext: 239
300
304
  Ciphertext: 324
301
305
  Overhead: 1.356
306
+ Groups: 1
302
307
  % soda es shared message -c raw -v > /dev/null
303
308
  Plaintext: 239
304
309
  Ciphertext: 372
305
310
  Overhead: 1.556
311
+ Groups: 1
306
312
  ```
307
313
 
308
314
 
@@ -311,12 +317,16 @@ Overhead: 1.556
311
317
  The rtty-soda supports various encodings:
312
318
 
313
319
  ```
314
- % soda encrypt-public alice bob_pub message --data-encoding base36 --group-len 5 --line-len 80
315
- 9TPUZ T8OA3 PNC2Z XEH87 EPMCN NDQJJ GX0DE YW16D OJ2FC D3PCM B148K 6UZFN 9RQX7
316
- 8C83X 6O8WS MQ4CX 26C7H 35EK5 CVSIX IFSVN KPV6A TRV1F 573WI JFFGE I7N3Z Z4N6D
317
- FSSOB DJUBK PC2YW Z6RG0 SUD2N OIYH8 WHJMN YYSKQ EBEVJ ZT0M1 DYJ7E NJ25J FMXNE
318
- 7LHUQ N5UIH SK5O7 96LWM IZ7BA R8SIV 6G55R Q50L4 PJH5Z 2JQNX JZTPK BG140 AKXOB
319
- DKR4K POW9A HCQSQ JLSJ1 11AZY P8BM4 F3GUC SFX04 RMD0G 4V0PL RLRHN G8D8
320
+ % soda encrypt-public alice bob_pub message --data-encoding base36 --group-len 5 --verbose
321
+ D0MQT LF0K5 N997D JJXZ9 K85DJ DCEIF 3I2BN GCYOG KN02L 5TPKE 4UV25 AKD0R O9BKS
322
+ 6Y40L T2NET GQKXA B4C4X 6J88W N4HZK 5ACFE 8JWTC UZJBH LRXPE CJLL5 N8L2I BX2NS
323
+ D9LYW H6EAT 1J2OA IHZC3 8L2JM 6XLS9 5M6Y2 E9FLU GHDVB WZWK7 WC2RQ OLQH6 OT725
324
+ 706MK ZSU6O V6PWA UHOTM XVFSK HE3OO M4E51 4R00I U3YL8 FJXFQ PZLM8 WYO6Z 50G5Q
325
+ SM6BH GT1T7 ZBSDB 8COJ6 7DXCF K7T36 RSU06 6R9AS J7TEA D9BT7 Q8BCG D4YX
326
+ Plaintext: 239
327
+ Ciphertext: 382
328
+ Overhead: 1.598
329
+ Groups: 64
320
330
  ```
321
331
 
322
332
 
@@ -0,0 +1,23 @@
1
+ rtty_soda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ rtty_soda/archivers.py,sha256=b-qZ6-MAY1rm1Jsosi2XEfjNjkU7acAedHmnSzthf-A,1343
3
+ rtty_soda/cli_io.py,sha256=feBDGyr-DQw8ALmsChM6V-MfusXdvv-2yE-It53w8JE,3064
4
+ rtty_soda/cryptography/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ rtty_soda/cryptography/kdf.py,sha256=HymfTiK7BD7lhZu0OdtFW_i-v0r7e8XedT8_Q84ClJc,1529
6
+ rtty_soda/cryptography/public.py,sha256=6gwsT4ilaMDHwtdYPOEYlX8IfwHPew8lMIbxRva1mLs,612
7
+ rtty_soda/cryptography/secret.py,sha256=N5ytktC2oxYfTFew0utytEClWK2rMvcnxlqeppR7wDQ,529
8
+ rtty_soda/encoders/__init__.py,sha256=y2_dw7PQRadBKZ6CSPOSqjHyxdiGJ_KmxXSsyQytugk,737
9
+ rtty_soda/encoders/base26_encoder.py,sha256=QXQJI4FBlW5p1rnTgi_D10eOqs86O2JxWHxbOprdenQ,482
10
+ rtty_soda/encoders/base31_encoder.py,sha256=0CIu2gtauL7XbPF1uyphlNI30sqeABsBqitinZmy4Sk,510
11
+ rtty_soda/encoders/base36_encoder.py,sha256=wlEMWGo_S4h7-bH2yYqTeObfdbEk6j3x0ebG4HEufvA,498
12
+ rtty_soda/encoders/base64_encoder.py,sha256=ZEkYHnTj7IeMX1yAHbeL-tLs2K2SaSspypgGB2N71Jw,316
13
+ rtty_soda/encoders/base94_encoder.py,sha256=Xbt0chbeAIM9_nRHVhRMVfMBUKS9q1gNSpg2WhGn2N4,487
14
+ rtty_soda/encoders/encoder.py,sha256=trHunjg0uNEQrQWTpRMY5nQEx5_jBrcvfUAcGIKpgms,220
15
+ rtty_soda/encoders/functions.py,sha256=JxtgbZg3kdbFqAhjm59QwJS6zEXYsR1m02k7cg_rFI4,1385
16
+ rtty_soda/encoders/raw_encoder.py,sha256=eJnUSsxf3jichdQ5LqwvBZAX7-qk67p5FMlfKOOGHp8,259
17
+ rtty_soda/main.py,sha256=yjEUe6pwIX_M6HfJ6ujCbYPElknW3zivKOLOSh8Q2h0,15891
18
+ rtty_soda/main.pyi,sha256=SoTM1GXACRafCtwwLOI1X9YhvEo3DPoaPtKSgWacSS0,2242
19
+ rtty_soda/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ rtty_soda-0.2.2.dist-info/WHEEL,sha256=M6du7VZflc4UPsGphmOXHANdgk8zessdJG0DBUuoA-U,78
21
+ rtty_soda-0.2.2.dist-info/entry_points.txt,sha256=tFROKkaDoE_p5tM2ko7MoAjWBFurchcw3j-MdObxBU0,45
22
+ rtty_soda-0.2.2.dist-info/METADATA,sha256=acIyNel7hAHcz1bsJmEWslmVefPFMYd4DT1CnAbKLno,9820
23
+ rtty_soda-0.2.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.9.3
2
+ Generator: uv 0.9.5
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,23 +0,0 @@
1
- rtty_soda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- rtty_soda/archivers.py,sha256=b-qZ6-MAY1rm1Jsosi2XEfjNjkU7acAedHmnSzthf-A,1343
3
- rtty_soda/cli_io.py,sha256=5c0Jt51zVgLHZMppj9sXl5x8nZsdpeTx7rglHE4w0wg,3170
4
- rtty_soda/cryptography/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- rtty_soda/cryptography/kdf.py,sha256=HymfTiK7BD7lhZu0OdtFW_i-v0r7e8XedT8_Q84ClJc,1529
6
- rtty_soda/cryptography/public.py,sha256=6gwsT4ilaMDHwtdYPOEYlX8IfwHPew8lMIbxRva1mLs,612
7
- rtty_soda/cryptography/secret.py,sha256=N5ytktC2oxYfTFew0utytEClWK2rMvcnxlqeppR7wDQ,529
8
- rtty_soda/encoders/__init__.py,sha256=y2_dw7PQRadBKZ6CSPOSqjHyxdiGJ_KmxXSsyQytugk,737
9
- rtty_soda/encoders/base26_encoder.py,sha256=E8JD9CKBNsANDi6-7RXobiB-GrWOJX0ThN8A7YtxjzM,459
10
- rtty_soda/encoders/base31_encoder.py,sha256=23mxVPJSJqrxzlTmGGaV7pvMxnJCArqO-_ZsVAl4UHA,486
11
- rtty_soda/encoders/base36_encoder.py,sha256=3mPM4nTy_a1BRBqZD5tCjcZGtgUjU3Ew2y4ro9qq-jg,475
12
- rtty_soda/encoders/base64_encoder.py,sha256=K1y7zVyb4d_YTrP5iONxtJ8hfJpCUcdCAOAoLppcPYk,294
13
- rtty_soda/encoders/base94_encoder.py,sha256=TP9OYBF9tzIvqbOr5YRRAQt1SCxvnrL1FVOsIbrX8jc,463
14
- rtty_soda/encoders/encoder.py,sha256=z-NPAqoxl5VlYLED_Zh0OaE7DR2BkStF10_YSaH1fOM,199
15
- rtty_soda/encoders/functions.py,sha256=JxtgbZg3kdbFqAhjm59QwJS6zEXYsR1m02k7cg_rFI4,1385
16
- rtty_soda/encoders/raw_encoder.py,sha256=wvOzPG9SvoEaOOOsLfHR8KIdAbSs_6RMAhIyuVmlNFw,237
17
- rtty_soda/main.py,sha256=g_IHKlQMpv4gquw8NfQVRxV5mv84dp0PsXQAwL49Vjo,16298
18
- rtty_soda/main.pyi,sha256=1_ahHQ89q7lC2cQ0Vgk4QXwsP0G9c10XYGvrVsO1U0s,2203
19
- rtty_soda/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- rtty_soda-0.2.0.dist-info/WHEEL,sha256=ELhySV62sOro8I5wRaLaF3TWxhBpkcDkdZUdAYLy_Hk,78
21
- rtty_soda-0.2.0.dist-info/entry_points.txt,sha256=tFROKkaDoE_p5tM2ko7MoAjWBFurchcw3j-MdObxBU0,45
22
- rtty_soda-0.2.0.dist-info/METADATA,sha256=Kt9mN0FEH1aPDnVuOwoWT-29hJFa6hH_Y7qt53qEsfE,9657
23
- rtty_soda-0.2.0.dist-info/RECORD,,