1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
|
# Dissononce
[](https://travis-ci.org/tgalal/dissononce)
[](https://pypi.python.org/pypi/dissononce)
Dissononce is a python implementation for [Noise Protocol Framework](https://noiseprotocol.org/).
A main goal of this project is to provide a simple, easy to read and understand practical reference for
Noise enthusiasts, implementers and users. Therefore this project attempts to stick to the following guidelines:
- Syntax that resembles as closely as possible definitions and pseudo code mentioned in Noise Specs.
- As minimal python "magic" as possible (explicit is better than implicit).
- Code that is simple, easy to read, follow and understand.
- Flexibility to easily adopt future changes to Noise specifications.
- Deviations from Noise Specs (additions, opinionated specs and API changes..etc) are isolated from original
implementation/API and are optional to use.
- Deviations from Noise Specs do not influence adjustments to original implementation/API that conflict with Noise Specs.
## META-INF
```
dissononce version: 0.34.3
noise revision: 34
released: 2019-04-24
requires:
- python>=2.5,<=3.7
- cryptography>=2.5
uses:
- transitions==0.6.9
```
## Contents
- [Installation](#installation)
- [Usage](#usage)
- [Crypto Functions](#crypto-functions)
- [Processing](#processing)
- [Handshake Patterns](#handshake-patterns)
- [Modifiers](#modifiers)
- [Extras](#extras)
- [Crypto functions by name](#meta-crypto-functions-by-name)
- [Noise Protocol by name](#meta-noise-protocols-by-name)
- [GuardedHandshakeState](#processing-guardedhandshakestate)
- [SwitchableHandshakeState](#processing-switchablehandshakestate)
- [NoGenDH](#nogendh)
- [Examples](#examples)
- [Testing](#testing)
- [Logging](#logging)
- [Appendices](#appendices)
## Installation
From source:
```
python setup.py install
```
Using Pip:
```
pip install dissononce
```
## Usage
### Crypto Functions
Each set of Crypto functions (DH, Cipher, Hash) is enclosed inside an own base class, where an implementation subclasses
that base class to implement the methods.
- DH-functions base class: ```dissononce.dh.dh.DH```
- Cipher-functions base class: ```dissononce.cipher.cipher.Cipher```
- Hash-functions base class: ```dissononce.hash.hash.Hash```
Example instantiating objects for X25519 ```DH```, AESGCM ```Cipher``` and SHA256 ```Hash```:
```python
from dissononce.cipher.aesgcm import AESGCMCipher
from dissononce.dh.x25519.x25519 import X25519DH
from dissononce.hash.sha256 import SHA256Hash
cipher = AESGCMCipher()
dh = X25519DH()
hash = SHA256Hash()
```
Implementations for each set of crypto functions are organized according to their support level:
- **stable:** officially covered in Noise spec, accessible under:
- [dissononce/dh/](dissononce/dh)
- [dissononce/cipher/](dissononce/cipher)
- [dissononce/hash/](dissononce/hash)
- **experimental:** recognized by Noise community, not officially covered in Noise spec or endorsed by it, found under:
- [dissononce/extras/dh/experimental/](dissononce/extras/dh/experimental/)
- [dissononce/extras/cipher/experimental/](dissononce/extras/cipher/experimental/)
- [dissononce/extras/hash/experimental/](dissononce/extras/hash/experimental/)
- **dangerous:** a monkey might have written those, **just don't use**:
- [dissononce/extras/dh/dangerous/](dissononce/extras/dh/dangerous/)
- [dissononce/extras/cipher/dangerous/](dissononce/extras/cipher/dangerous/)
- [dissononce/extras/hash/dangerous/](dissononce/extras/hash/dangerous/)
See [Appendices](#appendices) for available Crypto functions.
### Processing
```HandshakeState```, ```SymmetricState``` and ```CipherState``` should ideally be constructed in a composition-manner,
where Crypto-functions dependencies are also to be instantiated before passing them to their dependants.
- A ```CipherState``` requires a ```Cipher``` object
- A ```SymmetricState``` requires a ```CipherState``` and a ```Hash``` object.
- A ```HandshakeState``` requires a ```SymmetricState``` and a ```DH``` object.
```python
from dissononce.processing.impl.handshakestate import HandshakeState
from dissononce.processing.impl.symmetricstate import SymmetricState
from dissononce.processing.impl.cipherstate import CipherState
from dissononce.cipher.chachapoly import ChaChaPolyCipher
from dissononce.dh.x448.x448 import X448DH
from dissononce.hash.sha512 import SHA512Hash
handshakestate = HandshakeState(
SymmetricState(
CipherState(
ChaChaPolyCipher()
),
SHA512Hash()
),
X448DH()
)
```
See [Extras](#extras) for alternative methods of construction.
### Handshake Patterns
The ```HandshakePattern``` class allows authoring of patterns using a simple syntax, similar to how patterns are
described in Noise spec.
- message_patterns is a tuple/list of tuples of token(s).
- initiator_pre_messages is a tuple of tokens
- responder_pre_message_pattern is a tuple of tokens
```python
from dissononce.processing.handshakepatterns.handshakepattern import HandshakePattern
k1k1 = HandshakePattern(
name='K1K1',
initiator_pre_messages=('s',),
responder_pre_message_pattern=('s',),
message_patterns=(
('e',),
('e', 'ee', 'es'),
('se',)
)
)
print(k1k1)
```
```
K1K1:
-> s
<- s
...
-> e
<- e, ee, es
-> se
```
See [Appendices](#appendices) for already defined Handshake Patterns.
### Modifiers
A ```Modifier``` accepts a ```HandshakePattern``` and creates a new one with a modified name, and a modified set of
message and premessage patterns
**Fallback**
```python
from dissononce.processing.modifiers.fallback import FallbackPatternModifier
from dissononce.processing.handshakepatterns.interactive.XX import XXHandshakePattern
xx = XXHandshakePattern()
xx_fallback = FallbackPatternModifier().modify(xx)
print(xx_fallback)
```
```
XXfallback:
-> e
...
<- e, ee, s, es
-> s, se
```
**PSK**
```python
from dissononce.processing.modifiers.psk import PSKPatternModifier
from dissononce.processing.handshakepatterns.interactive.NN import NNHandshakePattern
nn = NNHandshakePattern()
nn_psk0 = PSKPatternModifier(0).modify(nn)
nn_psk02 = PSKPatternModifier(2).modify(nn_psk0)
print(nn_psk02)
```
```
NNpsk0+psk2:
-> psk, e
<- e, ee, psk
```
As usual, the modified ```HandshakePattern``` is used to (re)initialize a ```HandshakeState```:
```python
handshakestate.initialize(
handshake_pattern=nn_psk02,
initiator=True,
prologue=b'',
psks=(psk0, psk2)
)
```
### Extras
Classes and functions that are not part of Noise Protocol specification but are part of this implementation are referred
to as "Extras" or "Deviations". Examples for Extras are helpers, classes that simplify usage of the library, wrappers
that enforce some rules or design patterns, or crypto functions that are not part of Noise Spec. Extras should be
decoupled as much as possible from the base spec implementation and never referenced from there.
#### meta: Crypto-functions by name:
As an alternative to directly instantiating the Crypto-functions objects, they could also be created by name using
a factory designated to each type of Crypto-functions:
```python
from dissononce.extras.meta.hash.factory import HashFactory
from dissononce.extras.meta.dh.factory import DHFactory
from dissononce.extras.meta.cipher.factory import CipherFactory
cipher = CipherFactory().get_cipher('AESGCM')
hash = HashFactory().get_hash('SHA256')
dh = DHFactory().get_dh('25519')
```
Note that creating by name supports stable/official algorithms only at the moment.
#### meta: Protocol by name:
A Noise Protocol, that is:
- DH, Cipher, Hash instance
- CipherState instance
- SymmetricState instance
- HandshakeState instance
- HandshakePattern
can be created by name. Use ```NoiseProtocolFactory``` to get a a ```NoiseProtocol``` instance which encloses
instances of ```DH```, ```Cipher```, ```Hash```, ```HandshakePattern```, and exposes methods for creating
```CipherState```, ```SymmetricState```, and ```HandshakeState```.
```python
from dissononce.extras.meta.protocol.factory import NoiseProtocolFactory
protocol = NoiseProtocolFactory().get_noise_protocol('Noise_XX_25519_AESGCM_SHA256')
handshakestate = protocol.create_handshakestate()
```
Note that creating by name supports stable/official algorithms only at the moment.
#### processing: GuardedHandshakeState
```python
from dissononce.extras.processing.handshakestate_guarded import GuardedHandshakeState
guarded = GuardedHandshakeState(handshakestate)
guarded.read_message(b'', bytearray())
```
```
> AssertionError: Cannot read_message while in initialize phase.
```
```GuardedHandshakeState``` wraps an existing ```HandshakeState``` to enforce a correct flow of the handshake process.
This includes making sure the ```HandshakeState``` is initialized before usage, and that the flow order of
```write_message``` and ```read_message``` invocations match the ```HandshakePattern``` being used. A violation will
result in an AssertionError getting raised.
#### processing: SwitchableHandshakeState
```python
from dissononce.extras.processing.handshakestate_switchable import SwitchableHandshakeState
from dissononce.processing.handshakepatterns.interactive.XX import XXHandshakePattern
from dissononce.processing.modifiers.fallback import FallbackPatternModifier
from dissononce.extras.meta.protocol.factory import NoiseProtocolFactory
protocol = NoiseProtocolFactory().get_noise_protocol('Noise_IK_25519_AESGCM_SHA256')
switchable = SwitchableHandshakeState(protocol.create_handshakestate())
## Begin IK, then fallback to XX if necessary using:
switchable.switch(
handshake_pattern=FallbackPatternModifier().modify(XXHandshakePattern()),
initiator=True,
prologue=b''
)
```
```SwitchableHandshakeState``` facilitates transforming an ongoing Handshake into using a different pattern. Given
the new```HandshakePattern```, it analyses the required initiator and responder pre-messages, and maintains them
across the transformation for use in the new Handshake. This is typically used for example when doing
a ```IK``` handshake then switching to ```XXfallback``` where ```re``` is to be used as a initiator pre-message.
## Examples
Inside [examples](examples) directory there are examples for some Noise protocols carrying out a handshake and
transporting some messages for demonstration.
## Testing
### Test Vectors
Vectors used for testing are found under test/vectors. The data is of JSON type, and is formatted according
to [Noise Test Vectors Specification](https://github.com/noiseprotocol/noise_wiki/wiki/Test-vectors). At the moment
there are 2 Test Vectors files:
- Tests Vectors from [cacophony](https://github.com/centromere/cacophony) under [tests/vectors/cacophony.txt](tests/vectors/cacophony.txt)
- Test Vectors from [snow](https://github.com/mcginty/snow) under [tests/vectors/snow.txt](tests/vectors/snow.txt)
## Logging
Enable debug-level logging for a detailed insight of a handshake process. The debug output syntax and formatting is
intended to be as close as possible to the language used in Noise specs. This might be useful for when using dissononce
as a reference implementation where one wants to understand what's going on internally and to easily relate to
Noise specs.
```
>>> import dissononce, logging
>>> dissononce.logger.setLevel(logging.DEBUG)
>>> handshakestate.initialize(XXHandshakePattern(), True, b'', X448DH().generate_keypair())
I dissononce.processing.impl.handshakestate - Derived Noise Protocol name Noise_XX_448_ChaChaPoly_SHA512
XX:
-> e
<- e, ee, s, es
-> s, se
>>> handshakestate.write_message(b'',bytearray())
I dissononce.processing.impl.handshakestate - WriteMessage(payload, message_buffer)
D dissononce.processing.impl.handshakestate - Processing token 'e'
D dissononce.processing.impl.handshakestate - e=GENERATE_KEYPAIR()
D dissononce.processing.impl.handshakestate - message_buffer.append(e.public_key)
D dissononce.processing.impl.handshakestate - MixHash(e.public_key)
D dissononce.processing.impl.handshakestate - buffer.append(EncryptAndHash(payload))
```
## Appendices
### Cipher functions
Stable:
- [AESGCM](dissononce/cipher/aesgcm.py)
- [ChaChaPoly](dissononce/cipher/chachapoly.py)
### Hash functions
Stable:
- [Blake2b](dissononce/hash/blake2b.py)
- [Blake2s](dissononce/hash/blake2s.py)
- [SHA256](dissononce/hash/sha256.py)
- [SHA512](dissononce/hash/sha512.py)
### DH functions
Stable:
- [x448](dissononce/dh/x448/x448.py)
- [x25519](dissononce/dh/x25519/x25519.py)
### Handshake Patterns
Interactive:
- [IK](dissononce/processing/handshakepatterns/interactive/IK.py), [IN](dissononce/processing/handshakepatterns/interactive/IN.py), [IX](dissononce/processing/handshakepatterns/interactive/IX.py)
- [KK](dissononce/processing/handshakepatterns/interactive/KK.py), [KN](dissononce/processing/handshakepatterns/interactive/KN.py), [KX](dissononce/processing/handshakepatterns/interactive/KX.py)
- [NK](dissononce/processing/handshakepatterns/interactive/NK.py), [NN](dissononce/processing/handshakepatterns/interactive/NN.py), [NX](dissononce/processing/handshakepatterns/interactive/NX.py)
- [XK](dissononce/processing/handshakepatterns/interactive/XK.py), [XN](dissononce/processing/handshakepatterns/interactive/XN.py), [XX](dissononce/processing/handshakepatterns/interactive/XX.py)
Oneway:
- [K](dissononce/processing/handshakepatterns/oneway/K.py), [N](dissononce/processing/handshakepatterns/oneway/N.py), [X](dissononce/processing/handshakepatterns/oneway/X.py)
Deferred:
- [I1K](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/I1K.py),
[I1K1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/I1K1.py),
[I1N](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/I1N.py),
[I1X](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/I1X.py),
[I1X1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/I1X1.py),
[IK1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/IK1.py),
[IX1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/IX1.py)
- [K1K](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/K1K.py),
[K1K1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/K1K1.py),
[K1N](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/K1N.py),
[K1X](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/K1X.py),
[K1X1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/K1X1.py),
[KK1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/KK1.py),
[KX1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/KX1.py)
- [NK1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/NK1.py),
[NX1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/NX1.py)
- [X1K](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/X1K.py),
[X1K1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/X1K1.py),
[X1N](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/X1N.py),
[X1X](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/X1X.py),
[X1X1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/X1X1.py),
[XK1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/XK1.py),
[XX1](https://github.com/tgalal/dissononce/blob/master/dissononce/processing/handshakepatterns/deferred/XX1.py)
### Modifiers
- [fallback](dissononce/processing/modifiers/fallback.py)
- [psk](dissononce/processing/modifiers/psk.py)
## References
- [noise specs revision 34](https://github.com/noiseprotocol/noise_spec/releases/tag/v34)
- [noise mailing list](https://moderncrypto.org/mail-archive/noise/)
- [noiseprotocol for python3](https://github.com/plizonczyk/noiseprotocol)
- [noise-java](https://github.com/rweather/noise-java)
|