Skip to content

Commit 9360e50

Browse files
authored
Merge pull request #30 from 420neshot/larky_AES_CCM_GCM
New larky sample AES CCM-n-GCM
2 parents bd8d0bd + 5ff5e36 commit 9360e50

File tree

4 files changed

+245
-0
lines changed

4 files changed

+245
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# AES CCM and GCM sample of encryption in Larky
2+
3+
This sample includes:
4+
1. Python script that generates an ectrypted message of an input data;
5+
2. Larky test `.star` file that generates the same result of the same input data;
6+
3. Ready-for-use YAML (Inbound Route) that produces the same result as previous scripts.
7+
8+
## Testing part:
9+
10+
#### 1. Python:
11+
12+
Python script includes all hard-coded inside. As a result, it prints the encrypted message:
13+
```
14+
$ python python_sample.py
15+
16+
>>> Encrypted GCM: YXNkNDU2ZmdoMDEyql2O8UB53Ux94KWoIaIDarnm+6xKaXL2FNfHl5XOCtbv590W5x6ISEI3
17+
18+
>>> GCM decrypted: b'{"card_number":"4111111111111111"}'
19+
20+
>>> Encrypted CCM: YXNkNDU2ZmdoMDEysNf+zbjlTcFG/q1TPyuLIJwELXp6pSwIx1bwpV8Zw92S6G2FpI3OpWEJ
21+
22+
>>> CCM decrypted: b'{"card_number":"4111111111111111"}'
23+
24+
```
25+
26+
#### 2. Larky test:
27+
28+
To be able to run Larky locally, you'll need to setup your local environment:
29+
https://www.verygoodsecurity.com/docs/larky/test-larky-locally
30+
31+
Example of run:
32+
33+
<img width="1364" alt="image" src="https://user-images.githubusercontent.com/78090218/189484115-04cfb575-f39c-4e55-9f9e-1d0095650e63.png">
34+
35+
#### 3. YAML file:
36+
37+
Upload the YAML to your vault and run:
38+
```
39+
curl https://tntbmt67sc7.sandbox.verygoodproxy.com/post -k \
40+
-H "Content-type: application/json" \
41+
-d '{"card_number":"4111111111111111"}'
42+
```
43+
44+
Example of response:
45+
```
46+
"json": {
47+
"CCM": "YXNkNDU2ZmdoMDEysNf+zbjlTcFG/q1TPyuLIJwELXp6pSwIx1bwpV8Zw92S6G2FpI3OpWEJ",
48+
"CCM_decrypted": {
49+
"card_number": "4111111111111111"
50+
},
51+
"GCM": "YXNkNDU2ZmdoMDEyql2O8UB53Ux94KWoIaIDarnm+6xKaXL2FNfHl5XOCtbv590W5x6ISEI3",
52+
"GCM_decrypted": {
53+
"card_number": "4111111111111111"
54+
}
55+
```
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import builtins
2+
import json
3+
from requests.auth import HTTPProxyAuth
4+
import base64
5+
from Crypto.Cipher import AES
6+
7+
TAG_LENGTH = 8
8+
9+
session_key = b'vbfhg768ghvbfhg768ghvbfhg768gh12'
10+
nonce = b'asd456fgh012'
11+
12+
body = b'{"card_number":"4111111111111111"}'
13+
14+
cipher_aes = AES.new(session_key, AES.MODE_GCM, nonce=nonce, mac_len=TAG_LENGTH)
15+
ciphertext, tag = cipher_aes.encrypt_and_digest(body)
16+
ciphertext_tag = b"".join([cipher_aes.nonce, ciphertext, tag])
17+
result_GCM = base64.b64encode(ciphertext_tag).decode('utf-8')
18+
print('\n>>> Encrypted GCM: ', result_GCM)
19+
20+
#decrypt GCM:
21+
cipher = AES.new(session_key, AES.MODE_GCM, nonce=nonce)
22+
plaintext = cipher.decrypt(ciphertext)
23+
print("\n>>> GCM decrypted: " + str(plaintext))
24+
25+
cipher_aes = AES.new(session_key, AES.MODE_CCM, nonce=nonce, mac_len=TAG_LENGTH)
26+
ciphertext, tag = cipher_aes.encrypt_and_digest(body)
27+
ciphertext_tag = b"".join([cipher_aes.nonce, ciphertext, tag])
28+
result_CCM = base64.b64encode(ciphertext_tag).decode('utf-8')
29+
print('\n>>> Encrypted CCM: ', result_CCM)
30+
31+
#decrypt CCM:
32+
cipher = AES.new(session_key, AES.MODE_CCM, nonce=nonce)
33+
plaintext = cipher.decrypt(ciphertext)
34+
print("\n>>> CCM decrypted: " + str(plaintext) + '\n')
35+
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
load("@stdlib//unittest", "unittest")
2+
load("@vendor//asserts", "asserts")
3+
load("@vgs//http/request", "VGSHttpRequest")
4+
load("@stdlib//json", json="json")
5+
load("@stdlib//builtins", builtins="builtins")
6+
load("@vendor//Crypto/Cipher/AES", AES="AES")
7+
load("@stdlib//base64", base64="base64")
8+
9+
10+
def process(input, ctx):
11+
TAG_LENGTH = 8
12+
session_key = b'vbfhg768ghvbfhg768ghvbfhg768gh12'
13+
nonce = b'asd456fgh012'
14+
15+
body_str = str(input.body)
16+
body = json.loads(body_str)
17+
18+
# GCM:
19+
cipher_aes = AES.new(session_key, AES.MODE_GCM, nonce=nonce, mac_len=TAG_LENGTH)
20+
ciphertext, tag = cipher_aes.encrypt_and_digest(builtins.bytes(body_str, 'utf-8'))
21+
ciphertext_tag = b"".join([cipher_aes.nonce, ciphertext, tag])
22+
ciphertext_b64_GCM = base64.b64encode(ciphertext_tag).decode('utf-8')
23+
# decrypt:
24+
cipher = AES.new(session_key, AES.MODE_GCM, nonce=nonce)
25+
plaintext = cipher.decrypt(ciphertext)
26+
body['GCM'] = ciphertext_b64_GCM
27+
body['GCM_decrypted'] = json.loads(str(plaintext))
28+
29+
# CCM:
30+
cipher_aes = AES.new(session_key, AES.MODE_CCM, nonce=nonce, mac_len=TAG_LENGTH)
31+
ciphertext, tag = cipher_aes.encrypt_and_digest(builtins.bytes(body_str, 'utf-8'))
32+
ciphertext_tag = b"".join([cipher_aes.nonce, ciphertext, tag])
33+
ciphertext_b64_CCM = base64.b64encode(ciphertext_tag).decode('utf-8')
34+
# decrypt:
35+
cipher = AES.new(session_key, AES.MODE_CCM, nonce=nonce)
36+
plaintext = cipher.decrypt(ciphertext)
37+
body['CCM'] = ciphertext_b64_CCM
38+
body['CCM_decrypted'] = json.loads(str(plaintext))
39+
40+
body.pop('card_number')
41+
input.body = builtins.bytes(json.dumps(body))
42+
return input
43+
44+
45+
def test_process():
46+
headers = {}
47+
body = b'{"card_number":"4111111111111111"}'
48+
input = VGSHttpRequest("https://test.com", data=body, headers=headers, method='POST')
49+
response = process(input, None)
50+
expected_body = b'{"CCM":"YXNkNDU2ZmdoMDEysNf+zbjlTcFG/q1TPyuLIJwELXp6pSwIx1bwpV8Zw92S6G2FpI3OpWEJ","CCM_decrypted":{"card_number":"4111111111111111"},"GCM":"YXNkNDU2ZmdoMDEyql2O8UB53Ux94KWoIaIDarnm+6xKaXL2FNfHl5XOCtbv590W5x6ISEI3","GCM_decrypted":{"card_number":"4111111111111111"}}'
51+
print(response.body)
52+
print(expected_body)
53+
asserts.assert_that(response.body).is_equal_to(expected_body)
54+
55+
56+
def _testsuite():
57+
_suite = unittest.TestSuite()
58+
_suite.addTest(unittest.FunctionTestCase(test_process))
59+
return _suite
60+
61+
_runner = unittest.TextTestRunner()
62+
_runner.run(_testsuite())
63+
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
data:
2+
- attributes:
3+
created_at: '2021-04-26T09:55:37'
4+
destination_override_endpoint: 'https://echo.apps.verygood.systems'
5+
entries:
6+
- classifiers: {}
7+
config:
8+
condition: AND
9+
rules:
10+
- condition: null
11+
expression:
12+
field: PathInfo
13+
operator: matches
14+
type: string
15+
values:
16+
- /post
17+
- condition: null
18+
expression:
19+
field: ContentType
20+
operator: equals
21+
type: string
22+
values:
23+
- application/json
24+
id: 3e4ca047-23e2-4397-9a67-d673cedf4cc8
25+
id_selector: null
26+
operation: REDACT
27+
operations:
28+
- name: github.com/verygoodsecurity/common/compute/larky/http/Process
29+
parameters:
30+
script: |-
31+
load("@stdlib//base64", base64="base64")
32+
load("@stdlib//builtins", builtins="builtins")
33+
load("@stdlib//json", json="json")
34+
load("@stdlib//larky", larky="larky")
35+
load("@vendor//Crypto/Cipher/AES", AES="AES")
36+
load("@vgs//vault", "vault")
37+
38+
def process(input, ctx):
39+
TAG_LENGTH = 8
40+
session_key = b'vbfhg768ghvbfhg768ghvbfhg768gh12'
41+
nonce = b'asd456fgh012'
42+
43+
body_str = str(input.body)
44+
body = json.loads(body_str)
45+
46+
# GCM:
47+
cipher_aes = AES.new(session_key, AES.MODE_GCM, nonce=nonce, mac_len=TAG_LENGTH)
48+
ciphertext, tag = cipher_aes.encrypt_and_digest(builtins.bytes(body_str, 'utf-8'))
49+
ciphertext_tag = b"".join([cipher_aes.nonce, ciphertext, tag])
50+
ciphertext_b64_GCM = base64.b64encode(ciphertext_tag).decode('utf-8')
51+
# decrypt:
52+
cipher = AES.new(session_key, AES.MODE_GCM, nonce=nonce)
53+
plaintext = cipher.decrypt(ciphertext)
54+
body['GCM'] = ciphertext_b64_GCM
55+
body['GCM_decrypted'] = json.loads(str(plaintext))
56+
57+
# CCM:
58+
cipher_aes = AES.new(session_key, AES.MODE_CCM, nonce=nonce, mac_len=TAG_LENGTH)
59+
ciphertext, tag = cipher_aes.encrypt_and_digest(builtins.bytes(body_str, 'utf-8'))
60+
ciphertext_tag = b"".join([cipher_aes.nonce, ciphertext, tag])
61+
ciphertext_b64_CCM = base64.b64encode(ciphertext_tag).decode('utf-8')
62+
# decrypt:
63+
cipher = AES.new(session_key, AES.MODE_CCM, nonce=nonce)
64+
plaintext = cipher.decrypt(ciphertext)
65+
body['CCM'] = ciphertext_b64_CCM
66+
body['CCM_decrypted'] = json.loads(str(plaintext))
67+
68+
body.pop('card_number')
69+
input.body = builtins.bytes(json.dumps(body))
70+
return input
71+
phase: REQUEST
72+
public_token_generator: UUID
73+
targets:
74+
- body
75+
token_manager: PERSISTENT
76+
transformer: JSON_PATH
77+
transformer_config:
78+
- $.email
79+
transformer_config_map: null
80+
host_endpoint: (.*)\.verygoodproxy\.com
81+
id: c891d346-0e1b-49b8-99ac-0754d34f14f2
82+
ordinal: null
83+
port: 80
84+
protocol: http
85+
source_endpoint: '*'
86+
tags:
87+
name: echo.apps.verygood.systems-steel-blue-parallelogram
88+
source: RouteContainer
89+
updated_at: '2021-05-07T11:45:32'
90+
id: c891d346-0e1b-49b8-99ac-0754d34f14f2
91+
type: rule_chain
92+
version: 1

0 commit comments

Comments
 (0)