1
0
mirror of https://github.com/pintov/1c-jwt.git synced 2024-11-24 08:12:36 +02:00

Initial commit

Initial commit
This commit is contained in:
pintov 2017-04-14 13:39:29 +03:00
commit 0cb2431e9a
4 changed files with 333 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 Vasily Pintov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

41
README.md Normal file
View File

@ -0,0 +1,41 @@
1C JWT
=====
This is a pure 1C implementation of `RFC 7519 <https://tools.ietf.org/html/rfc7519>`.
Limitations
-----------
This implementation works only on 1C:Enterprise platform version 8.3.10.2168 or above.
The platform you may download here: <https://1c-dn.com/user/updates/1c_enterprise_platform_training_version/>
Supported algorithm HS256 only.
Installing
----------
Download modules Cryptography.bsl and JWT.bsl.
Put modules into the 1C application.
Usage
-----
```
SecretKey = "secret";
Payload = New Structure;
Payload.Insert("sub", "1234567890");
Payload.Insert("name", "John Doe");
Payload.Insert("admin", True);
Token = JWT.Encode(SecretKey, Payload);
DecodedPayload = JWT.Decode(Token, SecretKey);
```
Credits and License
-------------------
Author: Vasily Pintov <vasily@pintov.ru>
License: MIT

125
src/Cryptography.bsl Normal file
View File

@ -0,0 +1,125 @@
// Computes a Hash-based Message Authentication Code (HMAC)
//
// Parameters:
// Key - BinaryData - the key to use in the hash algorithm
// Message - BinaryData - the input to compute the hash code for
// HashFunc - HashFunction - the name of the hash algorithm to use for hashing
//
// Returns:
// BinaryData - The computed hash code
//
Function HMAC(Val SecretKey, Val Message, Val HashFunc) Export
If HashFunc = HashFunction.MD5 Then
BlSz = 16;
ElsIf HashFunc = HashFunction.SHA1 Then
BlSz = 20;
ElsIf HashFunc = HashFunction.SHA256 Then
BlSz = 64;
Else
Raise "HMAC: unsupported hash function: " + HashFunc;
EndIf;
EmptyBin = GetBinaryDataFromString("");
SecretKey = BinLeft(SecretKey, BlSz);
Ê0 = BinRightPad(SecretKey, BlSz, "0x00");
ipad = BinRightPad(EmptyBin, BlSz, "0x36");
k_ipad = BinBitwiseXOR(Ê0, ipad);
opad = BinRightPad(EmptyBin, BlSz, "0x5C");
k_opad = BinBitwiseXOR(Ê0, opad);
k_ipad_Message = BinConcat(k_ipad, Message);
k_opad_Hash = BinConcat(k_opad, Hash(k_ipad_Message, HashFunc));
res = Hash(k_opad_Hash, HashFunc);
Return res;
EndFunction
Function BinLeft(Val BinaryData, Val CountOfBytes)
DataReader = New DataReader(BinaryData);
MemoryStream = New MemoryStream();
DataWriter = New DataWriter(MemoryStream);
Buffer = DataReader.ReadIntoBinaryDataBuffer(CountOfBytes);
DataWriter.WriteBinaryDataBuffer(Buffer);
Return MemoryStream.CloseAndGetBinaryData();
EndFunction
Function BinRightPad(Val BinaryData, Val Length, Val HexString)
PadByte = NumberFromHexString(HexString);
DataReader = New DataReader(BinaryData);
MemoryStream = New MemoryStream();
DataWriter = New DataWriter(MemoryStream);
Buffer = DataReader.ReadIntoBinaryDataBuffer();
If Buffer.Size > 0 Then
DataWriter.WriteBinaryDataBuffer(Buffer);
EndIf;
For n = Buffer.Size + 1 To Length Do
DataWriter.WriteByte(PadByte);
EndDo;
Return MemoryStream.CloseAndGetBinaryData();
EndFunction
Function BinBitwiseXOR(Val BinaryData1, Val BinaryData2)
MemoryStream = New MemoryStream();
DataWriter = New DataWriter(MemoryStream);
DataReader1 = New DataReader(BinaryData1);
DataReader2 = New DataReader(BinaryData2);
Buffer1 = DataReader1.ReadIntoBinaryDataBuffer();
Buffer2 = DataReader2.ReadIntoBinaryDataBuffer();
If Buffer1.Size > Buffer2.Size Then
Buffer1.WriteBitwiseXor(0, Buffer2, Buffer2.Size);
DataWriter.WriteBinaryDataBuffer(Buffer1);
Else
Buffer2.WriteBitwiseXor(0, Buffer1, Buffer1.Size);
DataWriter.WriteBinaryDataBuffer(Buffer2);
EndIf;
res = MemoryStream.CloseAndGetBinaryData();
Return res;
EndFunction
Function Hash(Val Value, Val HashFunc)
DataHashing = New DataHashing(HashFunc);
DataHashing.Append(Value);
Return DataHashing.HashSum;
EndFunction
Function BinConcat(Val BinaryData1, Val BinaryData2)
MemoryStream = New MemoryStream();
DataWriter = New DataWriter(MemoryStream);
DataReader1 = New DataReader(BinaryData1);
DataReader2 = New DataReader(BinaryData2);
Buffer1 = DataReader1.ReadIntoBinaryDataBuffer();
Buffer2 = DataReader2.ReadIntoBinaryDataBuffer();
DataWriter.WriteBinaryDataBuffer(Buffer1);
DataWriter.WriteBinaryDataBuffer(Buffer2);
res = MemoryStream.CloseAndGetBinaryData();
Return res;
EndFunction

146
src/JWT.bsl Normal file
View File

@ -0,0 +1,146 @@
Function Encode(Val SecretKey, Val Payload = Undefined, Val ExtraHeaders = Undefined) Export
If Payload = Undefined Then
Payload = New Structure;
EndIf;
header = New Structure;
header.Insert("typ", "JWT");
header.Insert("alg", "HS256");
If ExtraHeaders <> Undefined Then
For Each eh In ExtraHeaders Do
header.Insert(eh.Key, eh.Value);
EndDo;
EndIf;
headerBytes = GetBinaryDataFromString(ComposeJSON(header));
payloadBytes = GetBinaryDataFromString(ComposeJSON(Payload));
segments = New Array;
segments.Add(Base64UrlEncode(headerBytes));
segments.Add(Base64UrlEncode(payloadBytes));
stringToSign = StrConcat(segments, ".");
signature = Cryptography.HMAC(
GetBinaryDataFromString(SecretKey),
GetBinaryDataFromString(stringToSign),
HashFunction.SHA256);
segments.Add(Base64UrlEncode(signature));
res = StrConcat(segments, ".");
Return res;
EndFunction
Function Decode(Val Token, Val SecretKey, Val Verify = True) Export
parts = StrSplit(Token, ".");
If parts.Count() <> 3 Then
Raise "JWT.Decode: Token must consist from 3 delimited by dot parts";
EndIf;
header = parts[0];
payload = parts[1];
crypto = Base64UrlDecode(parts[2]);
headerJson = GetStringFromBinaryData(Base64UrlDecode(header));
payloadJson = GetStringFromBinaryData(Base64UrlDecode(payload));
headerData = ParseJSON(headerJson);
payloadData = ParseJSON(payloadJson);
If Verify Then
If headerData.Property("alg") Then
If headerData.alg <> "HS256" Then
Raise "JWT.Decode: unsopported algorithm: " + headerData.alg;
EndIf;
Else
Raise "JWT.Decode: header doesn't contain field 'alg'";
EndIf;
signature = Cryptography.HMAC(
GetBinaryDataFromString(SecretKey),
GetBinaryDataFromString(header + "." + payload),
HashFunction.SHA256);
If Base64String(crypto) <> Base64String(signature) Then
Raise "JWT.Decode: Invalid signature";
EndIf;
EndIf;
Return payloadData;
EndFunction
Function Base64UrlEncode(Val input)
output = Base64String(input);
output = StrSplit(output, "=")[0]; // Remove any trailing '='s
output = StrReplace(output, Chars.CR + Chars.LF, "");
output = StrReplace(output, "+", "-"); // 62nd char of encoding
output = StrReplace(output, "/", "_"); // 63rd char of encoding
Return output;
EndFunction
Function Base64UrlDecode(Val input)
res = input;
res = StrReplace(input, "-", "+"); // 62nd char of encoding
res = StrReplace(res, "_", "/"); // 63rd char of encoding
m = StrLen(res) % 4;
If m = 1 Then
Raise "JWT.Base64UrlDecode: Illegal base64url string: " + input;
ElsIf m = 2 Then
res = res + "=="; // Two pad chars
ElsIf m = 3 Then
res = res + "="; // One pad char
EndIf;
return Base64Value(res);
EndFunction
Function ComposeJSON(Obj)
If Not ValueIsFilled(Obj) Then
Return Undefined;
EndIf;
JSONWriter = New JSONWriter;
Settings = New JSONWriterSettings(JSONLineBreak.None);
JSONWriter.SetString(Settings);
WriteJSON(JSONWriter, Obj);
Return JSONWriter.Close();
EndFunction
Function ParseJSON(Json) Export
If ValueIsNotFilled(Json) Then
Return Undefined;
EndIf;
JSONReader = New JSONReader;
JSONReader.SetString(Json);
Return ReadJSON(JSONReader, False);
EndFunction
Procedure Test() Export
SecretKey = "secret";
Payload = New Structure;
Payload.Insert("sub", "1234567890");
Payload.Insert("name", "John Doe");
Payload.Insert("admin", True);
Token = Encode(SecretKey, Payload);
DecodedPayload = Decode(Token, SecretKey);
EndProcedure