@@ -676,56 +676,71 @@ typedef struct {
676
676
/*
677
677
// chacha20: native [
678
678
// "Encrypt/decrypt data using ChaCha20 algorithm. Returns stream cipher context handle or encrypted/decrypted data."
679
- // /key "Provided only for the first time to get stream HANDLE! "
680
- // crypt-key [binary!] "Crypt key (16 or 32 bytes)."
681
- // nonce [binary!] "Initialization nonce (8 bytes) ."
679
+ // ctx [handle! binary!] "ChaCha20 handle and or binary key for initialization (16 or 32 bytes) "
680
+ // /init
681
+ // nonce [binary!] "Initialization nonce (IV) - 8 or 12 bytes."
682
682
// count [integer!] "A 32-bit block count parameter"
683
+ // /aad sequence [integer!] "Sequence number used with /init to modify nonce"
683
684
// /stream
684
- // ctx [handle!] "Stream cipher context."
685
685
// data [binary!] "Data to encrypt/decrypt."
686
686
// /into
687
687
// out [binary!] "Output buffer (NOT YET IMPLEMENTED)"
688
688
// ]
689
689
***********************************************************************/
690
690
{
691
- REBOOL ref_key = D_REF (1 );
692
- REBVAL * val_crypt_key = D_ARG (2 );
691
+ REBVAL * val_ctx = D_ARG (1 );
692
+ REBOOL ref_init = D_REF (2 );
693
693
REBVAL * val_nonce = D_ARG (3 );
694
- REBVAL * val_count = D_ARG (4 );
695
- REBOOL ref_stream = D_REF (5 );
696
- REBVAL * val_ctx = D_ARG (6 );
697
- REBVAL * val_data = D_ARG (7 );
698
- REBOOL ref_into = D_REF (8 );
699
-
700
- REBVAL * ret = D_RET ;
694
+ REBVAL * val_counter = D_ARG (4 );
695
+ REBOOL ref_aad = D_REF (5 );
696
+ REBVAL * val_sequence = D_ARG (6 );
697
+ REBOOL ref_stream = D_REF (7 );
698
+ REBVAL * val_data = D_ARG (8 );
699
+ REBOOL ref_into = D_REF ( 9 );
700
+
701
701
REBSER * ctx_ser ;
702
702
REBINT len ;
703
+ REBU64 sequence ;
703
704
704
- if (ref_key ) {
705
- //key defined - setup new context
706
-
707
- len = VAL_LEN (val_crypt_key );
708
-
709
- if (len != 16 && len != 32 && VAL_LEN (val_nonce ) != 8 ) {
705
+ if (IS_BINARY (val_ctx )) {
706
+ len = VAL_LEN (val_ctx );
707
+ if (!(len == 32 || len == 16 )) {
708
+ printf ("ChaCha20 key must be of size 32 or 16 bytes! Is: %i\n" , len );
709
+ Trap1 (RE_INVALID_DATA , val_ctx );
710
710
return R_NONE ;
711
711
}
712
-
713
712
//making series from POOL so it will be GCed automaticaly
714
713
ctx_ser = Make_Series (sizeof (chacha20_ctx ), (REBCNT )1 , FALSE);
714
+
715
+ chacha20_keysetup ((chacha20_ctx * )ctx_ser -> data , VAL_BIN_AT (val_ctx ), len );
716
+
715
717
SERIES_TAIL (ctx_ser ) = sizeof (chacha20_ctx );
718
+ SET_HANDLE (val_ctx , ctx_ser , SYM_CHACHA20 , HANDLE_SERIES );
719
+ // the ctx_ser in the handle is released by GC once the handle is not referenced
720
+ }
721
+ else {
722
+ ctx_ser = VAL_HANDLE_DATA (val_ctx );
723
+ if (VAL_HANDLE_TYPE (val_ctx ) != SYM_CHACHA20 || ctx_ser == NULL || SERIES_TAIL (ctx_ser ) != sizeof (chacha20_ctx )){
724
+ Trap0 (RE_INVALID_HANDLE );
725
+ }
726
+ }
716
727
717
- chacha20_setup (
718
- (chacha20_ctx * )ctx_ser -> data ,
719
- VAL_BIN_AT (val_crypt_key ),
720
- len ,
721
- VAL_BIN_AT (val_nonce )
722
- );
723
- chacha20_counter_set ((chacha20_ctx * )ctx_ser -> data , VAL_INT64 (val_count ));
728
+ if (ref_init ) {
729
+ // initialize nonce with counter
730
+
731
+ len = VAL_LEN (val_nonce );
724
732
725
- SET_HANDLE (ret , ctx_ser , SYM_CHACHA20 , HANDLE_SERIES );
726
- // the ctx in the handle is released by GC once the handle is not referenced
733
+ if (!(len == 12 || len == 8 )) {
734
+ Trap1 (RE_INVALID_DATA , val_nonce );
735
+ return R_NONE ;
736
+ }
727
737
728
- } else if (ref_stream ) {
738
+ sequence = (ref_aad ) ? VAL_INT64 (val_sequence ) : 0 ;
739
+ chacha20_ivsetup ((chacha20_ctx * )ctx_ser -> data , VAL_BIN_AT (val_nonce ), len , VAL_INT64 (val_counter ), (u8 * )& sequence );
740
+
741
+ }
742
+
743
+ if (ref_stream ) {
729
744
730
745
ctx_ser = VAL_HANDLE_DATA (val_ctx );
731
746
@@ -746,11 +761,11 @@ typedef struct {
746
761
len
747
762
);
748
763
749
- SET_BINARY (ret , binaryOut );
750
- VAL_TAIL (ret ) = len ;
764
+ SET_BINARY (val_ctx , binaryOut );
765
+ VAL_TAIL (val_ctx ) = len ;
751
766
752
767
}
753
- return R_RET ;
768
+ return R_ARG1 ;
754
769
}
755
770
756
771
@@ -777,7 +792,7 @@ typedef struct {
777
792
REBVAL * val_mac = D_ARG (6 );
778
793
779
794
REBVAL * ret = D_RET ;
780
- REBSER * ctx_ser , * bin ;
795
+ REBSER * ctx_ser ;
781
796
REBINT len ;
782
797
REBCNT i ;
783
798
REBYTE mac [16 ];
@@ -824,4 +839,173 @@ typedef struct {
824
839
}
825
840
826
841
return R_ARG1 ;
827
- }
842
+ }
843
+
844
+ /***********************************************************************
845
+ **
846
+ */ REBNATIVE (chacha20poly1305 )
847
+ /*
848
+ // chacha20poly1305: native [
849
+ // "..."
850
+ // ctx [none! handle!]
851
+ // /init
852
+ // local-key [binary!]
853
+ // local-iv [binary!]
854
+ // remote-key [binary!]
855
+ // remote-iv [binary!]
856
+ // /encrypt
857
+ // data-out [binary!]
858
+ // aad-out [binary!]
859
+ // /decrypt
860
+ // data-in [binary!]
861
+ // aad-in [binary!]
862
+ // ]
863
+ ***********************************************************************/
864
+ {
865
+ REBVAL * val_ctx = D_ARG (1 );
866
+ REBOOL ref_init = D_REF (2 );
867
+ REBVAL * val_local_key = D_ARG (3 );
868
+ REBVAL * val_local_iv = D_ARG (4 );
869
+ REBVAL * val_remote_key = D_ARG (5 );
870
+ REBVAL * val_remote_iv = D_ARG (6 );
871
+ REBOOL ref_encrypt = D_REF (7 );
872
+ REBVAL * val_plain = D_ARG (8 );
873
+ REBVAL * val_local_aad = D_ARG (9 );
874
+ REBOOL ref_decrypt = D_REF (10 );
875
+ REBVAL * val_cipher = D_ARG (11 );
876
+ REBVAL * val_remote_aad = D_ARG (12 );
877
+
878
+ REBSER * ctx_ser ;
879
+ REBINT len ;
880
+ chacha20poly1305_ctx * chacha ;
881
+ unsigned char poly1305_key [POLY1305_KEYLEN ];
882
+ size_t aad_size ;
883
+
884
+ if (ref_init ) {
885
+ ctx_ser = Make_Series (sizeof (chacha20poly1305_ctx ), (REBCNT )1 , FALSE);
886
+ SERIES_TAIL (ctx_ser ) = sizeof (chacha20poly1305_ctx );
887
+ SET_HANDLE (val_ctx , ctx_ser , SYM_CHACHA20POLY1305 , HANDLE_SERIES );
888
+ //SET_BINARY(val_ctx, ctx_ser);
889
+
890
+ chacha = (chacha20poly1305_ctx * )ctx_ser -> data ;
891
+ len = VAL_LEN (val_local_key );
892
+ if (!(len == 32 || len == 16 ))
893
+ Trap1 (RE_INVALID_DATA , val_local_key );
894
+ chacha20_keysetup (& chacha -> local_chacha , VAL_BIN_AT (val_local_key ), len );
895
+ len = VAL_LEN (val_remote_key );
896
+ if (!(len == 32 || len == 16 ))
897
+ Trap1 (RE_INVALID_DATA , val_remote_key );
898
+ chacha20_keysetup (& chacha -> remote_chacha , VAL_BIN_AT (val_remote_key ), len );
899
+
900
+ chacha -> local_sequence = 0 ;
901
+ chacha -> remote_sequence = 0 ;
902
+
903
+ len = VAL_LEN (val_local_iv );
904
+ if (!(len == 12 || len == 8 ))
905
+ Trap1 (RE_INVALID_DATA , val_local_iv );
906
+ chacha20_ivsetup (& chacha -> local_chacha , VAL_BIN_AT (val_local_iv ), len , 1 , (u8 * )& chacha -> local_sequence );
907
+ memcpy (chacha -> local_iv , VAL_BIN_AT (val_local_iv ), len );
908
+
909
+ len = VAL_LEN (val_remote_iv );
910
+ if (!(len == 12 || len == 8 ))
911
+ Trap1 (RE_INVALID_DATA , val_remote_iv );
912
+ chacha20_ivsetup (& chacha -> remote_chacha , VAL_BIN_AT (val_remote_iv ), len , 1 , (u8 * )& chacha -> remote_sequence );
913
+ memcpy (chacha -> remote_iv , VAL_BIN_AT (val_remote_iv ), len );
914
+ return R_ARG1 ;
915
+ }
916
+
917
+ ctx_ser = VAL_HANDLE_DATA (val_ctx );
918
+ if (VAL_HANDLE_TYPE (val_ctx ) != SYM_CHACHA20POLY1305 || ctx_ser == NULL || SERIES_TAIL (ctx_ser ) != sizeof (chacha20poly1305_ctx )){
919
+ Trap0 (RE_INVALID_HANDLE );
920
+ return R_NONE ;
921
+ }
922
+ chacha = (chacha20poly1305_ctx * )ctx_ser -> data ;
923
+
924
+ if (ref_encrypt ) {
925
+ chacha20_ivsetup (& chacha -> local_chacha , chacha -> local_iv , 12 , 1 , (u8 * )& chacha -> local_sequence );
926
+ chacha20_poly1305_key (& chacha -> local_chacha , poly1305_key );
927
+ //puts("poly1305_key:"); Dump_Bytes(poly1305_key, POLY1305_KEYLEN);
928
+
929
+ len = VAL_LEN (val_plain ) + POLY1305_TAGLEN ;
930
+ ctx_ser = Make_Series (len , (REBCNT )1 , FALSE);
931
+
932
+ // AEAD
933
+ // sequence number (8 bytes)
934
+ // content type (1 byte)
935
+ // version (2 bytes)
936
+ // length (2 bytes)
937
+ unsigned char aad [13 ];
938
+ aad_size = sizeof (aad );
939
+ unsigned char * sequence = aad ;
940
+
941
+ chacha20_poly1305_aead (& chacha -> local_chacha , VAL_BIN_AT (val_plain ), (REBCNT )len - POLY1305_TAGLEN , VAL_BIN_AT (val_local_aad ), VAL_LEN (val_local_aad ), poly1305_key , ctx_ser -> data );
942
+
943
+ //chacha->local_sequence++;
944
+
945
+ SERIES_TAIL (ctx_ser ) = len ;
946
+ SET_BINARY (val_ctx , ctx_ser );
947
+ return R_ARG1 ;
948
+ }
949
+
950
+ if (ref_decrypt ) {
951
+ static unsigned char zeropad [] = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
952
+ unsigned char trail [16 ];
953
+ unsigned char mac_tag [POLY1305_TAGLEN ];
954
+
955
+ chacha20_ivsetup (& chacha -> remote_chacha , chacha -> remote_iv , 12 , 1 , VAL_BIN_AT (val_remote_aad ));
956
+
957
+ len = VAL_LEN (val_cipher ) - POLY1305_TAGLEN ;
958
+ if (len <= 0 )
959
+ return R_NONE ;
960
+
961
+ ctx_ser = Make_Series (len , (REBCNT )1 , FALSE);
962
+
963
+ //puts("\nDECRYPT:");
964
+
965
+ chacha20_encrypt (& chacha -> remote_chacha , VAL_BIN_AT (val_cipher ), ctx_ser -> data , len );
966
+ //chacha_encrypt_bytes(&chacha->remote_chacha, VAL_BIN_AT(val_cipher), ctx_ser->data, len);
967
+ chacha20_poly1305_key (& chacha -> remote_chacha , poly1305_key );
968
+ //puts("poly1305_key:"); Dump_Bytes(poly1305_key, POLY1305_KEYLEN);
969
+
970
+ poly1305_context aead_ctx ;
971
+ poly1305_init (& aead_ctx , poly1305_key );
972
+
973
+ aad_size = VAL_LEN (val_remote_aad );
974
+ poly1305_update (& aead_ctx , VAL_BIN_AT (val_remote_aad ), aad_size );
975
+ int rem = aad_size % 16 ;
976
+ if (rem )
977
+ poly1305_update (& aead_ctx , zeropad , 16 - rem );
978
+ //puts("update:"); Dump_Bytes(VAL_BIN_AT(val_cipher), len);
979
+ poly1305_update (& aead_ctx , VAL_BIN_AT (val_cipher ), len );
980
+ rem = len % 16 ;
981
+ if (rem )
982
+ poly1305_update (& aead_ctx , zeropad , 16 - rem );
983
+
984
+ U32TO8_LE (& trail [0 ], aad_size == 5 ? 5 : 13 );
985
+ * (int * )& trail [4 ] = 0 ;
986
+ U32TO8_LE (& trail [8 ], len );
987
+ * (int * )& trail [12 ] = 0 ;
988
+
989
+ //puts("trail:"); Dump_Bytes(trail, 16);
990
+
991
+ poly1305_update (& aead_ctx , trail , 16 );
992
+ poly1305_finish (& aead_ctx , mac_tag );
993
+
994
+ if (!poly1305_verify (mac_tag , VAL_BIN_TAIL (val_cipher ) - POLY1305_TAGLEN )) {
995
+ puts ("MAC verification failed!" );
996
+ }
997
+ else {
998
+ puts ("MAC OK!" );
999
+ }
1000
+
1001
+ //puts("mac result:"); Dump_Bytes(mac_tag, POLY1305_TAGLEN);
1002
+
1003
+ chacha -> remote_sequence ++ ;
1004
+
1005
+
1006
+
1007
+ SERIES_TAIL (ctx_ser ) = len ;
1008
+ SET_BINARY (val_ctx , ctx_ser );
1009
+ }
1010
+ return R_ARG1 ;
1011
+ }
0 commit comments