Skip to content

Commit bd8d0bd

Browse files
authored
Merge pull request #29 from 420neshot/larky_aes_ctr
New Larky AES_CTR sample
2 parents 8454a3d + 2eeaec8 commit bd8d0bd

File tree

4 files changed

+247
-0
lines changed

4 files changed

+247
-0
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# AES CTR 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+
JmVuY3J5cHRlZERhdGE9UnMxSHg0NGZROWVFUXpKaVRGSHBSWU93a0NIS0lpZmxLVFhlLXAtWmlBMDhDa3VHWF96c2x3TzROa2Nfd0dZVzlBcVVTenEzT1NyN2RLOEo1c05WU20zQ0xtckU0ejFhNnRCYnE2TjN5dmdnVXhLb1JTVWp4Nnp4Z1dYTm1BZDdrZjVyYlhydlhnR2UwZVZjdlBFQUE3ZkVmbUJYZDdMM2pWT1JKekJIMGdMWDE0Ry1vQ2pFQVg0VmcxQ2xUbnQwZmVva255VXphczVUcHJld1dGOUJoQ1kzN3VYTVM2U2pNalJiRmc9PSZpdj1zZUJoZU5OWXpFVVJ1eVFS
16+
```
17+
18+
#### 2. Larky test:
19+
20+
To be able to run Larky locally, you'll need to setup your local environment:
21+
https://www.verygoodsecurity.com/docs/larky/test-larky-locally
22+
23+
Example of run:
24+
25+
<img width="1367" alt="image" src="https://user-images.githubusercontent.com/78090218/189316028-377edbbd-14c2-42be-ad83-5be87a11607d.png">
26+
27+
#### 3. YAML file:
28+
29+
Upload the YAML to your vault and run:
30+
```
31+
curl https://tntbmt67sc7.sandbox.verygoodproxy.com/post -k \
32+
-H "Content-type: application/json" \
33+
-d '{
34+
"query": "MID=4111111111111111&exp_year=2030&exp_month=09&cvv=123&name=CoreyTaylor&amount=100",
35+
"python": "JmVuY3J5cHRlZERhdGE9UnMxSHg0NGZROWVFUXpKaVRGSHBSWU93a0NIS0lpZmxLVFhlLXAtWmlBMDhDa3VHWF96c2x3TzROa2Nfd0dZVzlBcVVTenEzT1NyN2RLOEo1c05WU20zQ0xtckU0ejFhNnRCYnE2TjN5dmdnVXhLb1JTVWp4Nnp4Z1dYTm1BZDdrZjVyYlhydlhnR2UwZVZjdlBFQUE3ZkVmbUJYZDdMM2pWT1JKekJIMGdMWDE0Ry1vQ2pFQVg0VmcxQ2xUbnQwZmVva255VXphczVUcHJld1dGOUJoQ1kzN3VYTVM2U2pNalJiRmc9PSZpdj1zZUJoZU5OWXpFVVJ1eVFS"
36+
}'
37+
```
38+
39+
Example of response:
40+
```
41+
"json": {
42+
"larky_": "JmVuY3J5cHRlZERhdGE9UnMxSHg0NGZROWVFUXpKaVRGSHBSWU93a0NIS0lpZmxLVFhlLXAtWmlBMDhDa3VHWF96c2x3TzROa2Nfd0dZVzlBcVVTenEzT1NyN2RLOEo1c05WU20zQ0xtckU0ejFhNnRCYnE2TjN5dmdnVXhLb1JTVWp4Nnp4Z1dYTm1BZDdrZjVyYlhydlhnR2UwZVZjdlBFQUE3ZkVmbUJYZDdMM2pWT1JKekJIMGdMWDE0Ry1vQ2pFQVg0VmcxQ2xUbnQwZmVva255VXphczVUcHJld1dGOUJoQ1kzN3VYTVM2U2pNalJiRmc9PSZpdj1zZUJoZU5OWXpFVVJ1eVFS",
43+
"python": "JmVuY3J5cHRlZERhdGE9UnMxSHg0NGZROWVFUXpKaVRGSHBSWU93a0NIS0lpZmxLVFhlLXAtWmlBMDhDa3VHWF96c2x3TzROa2Nfd0dZVzlBcVVTenEzT1NyN2RLOEo1c05WU20zQ0xtckU0ejFhNnRCYnE2TjN5dmdnVXhLb1JTVWp4Nnp4Z1dYTm1BZDdrZjVyYlhydlhnR2UwZVZjdlBFQUE3ZkVmbUJYZDdMM2pWT1JKekJIMGdMWDE0Ry1vQ2pFQVg0VmcxQ2xUbnQwZmVva255VXphczVUcHJld1dGOUJoQ1kzN3VYTVM2U2pNalJiRmc9PSZpdj1zZUJoZU5OWXpFVVJ1eVFS"
44+
}
45+
```
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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//builtins", builtins="builtins")
32+
load("@stdlib//json", json="json")
33+
load("@vgs//vault", "vault")
34+
load("@stdlib//hashlib", "hashlib")
35+
load("@stdlib//binascii", "binascii")
36+
load("@vgs//vault", "vault")
37+
load("@stdlib//base64", base64="base64")
38+
load("@vendor//Crypto/Hash/HMAC", HMAC="HMAC")
39+
load("@stdlib//string", string="string")
40+
load("@stdlib//random", random="random") # instead of 'secrets'
41+
load("@vendor//Crypto/Cipher/AES", AES="AES")
42+
load("@vendor//Crypto/Util/Counter", Counter="Counter") # correct?
43+
load("@vendor//Crypto/Hash/SHA256", SHA256="SHA256")
44+
45+
def process(input, ctx):
46+
API_SECRET = '5243A220F218587596BC3A9E3C47A4E7B4FF98F7136856F174940D22071A35DD'
47+
secondKey = 'MDIzM1OCNkMzRDTJGNDIc0MM1MkEz0NTA0E3Rjk5NDc='
48+
49+
body_str = str(input.body)
50+
body = json.loads(body_str)
51+
query = body['query']
52+
53+
# hashpart
54+
secret = bytes(API_SECRET, encoding='utf-8')
55+
query_tohash = query + API_SECRET
56+
hashValue = HMAC.new(secret, bytes(query_tohash, encoding='utf-8'), digestmod=SHA256)
57+
print (hashValue.hexdigest())
58+
59+
# Aes CTR encryption part
60+
to_encrypt = query + '&alg=SHA256&hashed_query='+hashValue.hexdigest()
61+
ivv = 'seBheNNYzEURuyQR' # made it static to compare with Python
62+
secondKey = base64.b64decode(secondKey)
63+
h = binascii.hexlify(bytes(ivv,encoding='utf-8'))
64+
ctr = Counter.new(128, initial_value=int(str(h), 16))
65+
chiper = AES.new(secondKey, AES.MODE_CTR, counter=ctr)
66+
chipertext = chiper.encrypt(bytes(to_encrypt,encoding='utf-8'))
67+
encString = base64.urlsafe_b64encode(chipertext).decode()
68+
payload = '&encryptedData=' + encString + '&iv=' + ivv
69+
70+
# final result to be send to dev.finexusgroup.com
71+
enc = bytes(payload, encoding='utf-8')
72+
final = base64.b64encode(enc).decode()
73+
74+
body['larky_'] = final
75+
body.pop('query')
76+
77+
input.body = builtins.bytes(json.dumps(body))
78+
return input
79+
phase: REQUEST
80+
public_token_generator: UUID
81+
targets:
82+
- body
83+
token_manager: PERSISTENT
84+
transformer: JSON_PATH
85+
transformer_config:
86+
- $.email
87+
transformer_config_map: null
88+
host_endpoint: (.*)\.verygoodproxy\.com
89+
id: c891d346-0e1b-49b8-99ac-0754d34f14f2
90+
ordinal: null
91+
port: 80
92+
protocol: http
93+
source_endpoint: '*'
94+
tags:
95+
name: echo.apps.verygood.systems-steel-blue-parallelogram
96+
source: RouteContainer
97+
updated_at: '2021-05-07T11:45:32'
98+
id: c891d346-0e1b-49b8-99ac-0754d34f14f2
99+
type: rule_chain
100+
version: 1
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import hmac
2+
import hashlib
3+
import base64
4+
import secrets
5+
from Crypto.Cipher import AES
6+
from Crypto.Util import Counter
7+
import binascii
8+
from base64 import b64encode
9+
import string
10+
API_SECRET = '5243A220F218587596BC3A9E3C47A4E7B4FF98F7136856F174940D22071A35DD'
11+
query = 'MID=4111111111111111&exp_year=2030&exp_month=09&cvv=123&name=CoreyTaylor&amount=100'
12+
secondKey = 'MDIzM1OCNkMzRDTJGNDIc0MM1MkEz0NTA0E3Rjk5NDc='
13+
14+
"""hashpart"""
15+
secret = API_SECRET.encode()
16+
query_tohash = query + API_SECRET
17+
hashValue = hmac.new(secret,bytes(query_tohash, encoding='utf-8'),digestmod=hashlib.sha256)
18+
19+
"""Aes CTR encryption part"""
20+
to_encrypt = query + '&alg=SHA256&hashed_query=' + hashValue.hexdigest()
21+
secondKey = base64.b64decode(secondKey)
22+
ivv = 'seBheNNYzEURuyQR'
23+
h = binascii.hexlify(bytes(ivv,encoding='utf-8'))
24+
ctr = Counter.new(128, initial_value=int(h, 16))
25+
chiper = AES.new(secondKey, AES.MODE_CTR, counter=ctr)
26+
chipertext = chiper.encrypt(bytes(to_encrypt,encoding='utf-8'))
27+
encString = base64.urlsafe_b64encode(chipertext).decode()
28+
payload = '&encryptedData='+encString+'&iv='+ivv
29+
30+
""" final result to be send"""
31+
print(base64.b64encode(payload.encode()).decode())
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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("@stdlib//hashlib", "hashlib")
7+
load("@stdlib//binascii", "binascii")
8+
load("@vgs//vault", "vault")
9+
load("@stdlib//base64", base64="base64")
10+
load("@vendor//Crypto/Hash/HMAC", HMAC="HMAC")
11+
load("@stdlib//string", string="string")
12+
load("@stdlib//random", random="random") # instead of 'secrets'
13+
load("@vendor//Crypto/Cipher/AES", AES="AES")
14+
load("@vendor//Crypto/Util/Counter", Counter="Counter") # correct?
15+
load("@vendor//Crypto/Hash/SHA256", SHA256="SHA256")
16+
17+
18+
def process(input, ctx):
19+
API_SECRET = '5243A220F218587596BC3A9E3C47A4E7B4FF98F7136856F174940D22071A35DD'
20+
secondKey = 'MDIzM1OCNkMzRDTJGNDIc0MM1MkEz0NTA0E3Rjk5NDc='
21+
22+
body_str = str(input.body)
23+
body = json.loads(body_str)
24+
query = body['query']
25+
26+
"""hashpart"""
27+
secret = bytes(API_SECRET, encoding='utf-8')
28+
query_tohash = query+API_SECRET
29+
hashValue = HMAC.new(secret, bytes(query_tohash, encoding='utf-8'), digestmod=SHA256)
30+
print (hashValue.hexdigest())
31+
32+
"""Aes CTR encryption part"""
33+
to_encrypt = query + '&alg=SHA256&hashed_query='+hashValue.hexdigest()
34+
ivv = 'seBheNNYzEURuyQR' # made it static to compare with Python
35+
secondKey = base64.b64decode(secondKey)
36+
h = binascii.hexlify(bytes(ivv,encoding='utf-8'))
37+
ctr = Counter.new(128, initial_value=int(str(h), 16))
38+
chiper = AES.new(secondKey, AES.MODE_CTR, counter=ctr)
39+
chipertext = chiper.encrypt(bytes(to_encrypt,encoding='utf-8'))
40+
encString = base64.urlsafe_b64encode(chipertext).decode()
41+
payload = '&encryptedData='+encString+'&iv='+ivv
42+
43+
""" final result to be send"""
44+
enc = bytes(payload, encoding='utf-8')
45+
final = base64.b64encode(enc).decode()
46+
47+
body['larky_'] = final
48+
body.pop('query')
49+
50+
input.body = builtins.bytes(json.dumps(body))
51+
return input
52+
53+
54+
def test_process():
55+
headers = {}
56+
body = b'{"query": "MID=4111111111111111&exp_year=2030&exp_month=09&cvv=123&name=CoreyTaylor&amount=100"}'
57+
input = VGSHttpRequest("https://test.com", data=body, headers=headers, method='POST')
58+
response = process(input, None)
59+
expected_body = b'{"larky_":"JmVuY3J5cHRlZERhdGE9UnMxSHg0NGZROWVFUXpKaVRGSHBSWU93a0NIS0lpZmxLVFhlLXAtWmlBMDhDa3VHWF96c2x3TzROa2Nfd0dZVzlBcVVTenEzT1NyN2RLOEo1c05WU20zQ0xtckU0ejFhNnRCYnE2TjN5dmdnVXhLb1JTVWp4Nnp4Z1dYTm1BZDdrZjVyYlhydlhnR2UwZVZjdlBFQUE3ZkVmbUJYZDdMM2pWT1JKekJIMGdMWDE0Ry1vQ2pFQVg0VmcxQ2xUbnQwZmVva255VXphczVUcHJld1dGOUJoQ1kzN3VYTVM2U2pNalJiRmc9PSZpdj1zZUJoZU5OWXpFVVJ1eVFS"}'
60+
print(response.body)
61+
print(expected_body)
62+
asserts.assert_that(response.body).is_equal_to(expected_body)
63+
64+
65+
def _testsuite():
66+
_suite = unittest.TestSuite()
67+
_suite.addTest(unittest.FunctionTestCase(test_process))
68+
return _suite
69+
70+
_runner = unittest.TextTestRunner()
71+
_runner.run(_testsuite())

0 commit comments

Comments
 (0)