diff -uNr a/smg_comms/c_wrappers/tests/tests.c b/smg_comms/c_wrappers/tests/tests.c --- a/smg_comms/c_wrappers/tests/tests.c c40e451a3093c41c8c5762c284a1e05716c2e429ee7e56c1e93bb2adbff0d83fdba237dc01510891a362eecbf9c908501468a3747c4a735ff90d407504abe1f8 +++ b/smg_comms/c_wrappers/tests/tests.c 62807ed879ed8e0089ed1f605c51603005a18c813cfff19df7721478823c6886bf609075d82c1022a4a849b62d573d9fea1d20c49db1b37f6950c6326e5b5c87 @@ -144,78 +144,72 @@ //key pair previously generated with EuCrypt mpi_fromstr(sk.n, "0x\ -CD2C025323BEA46FFF2FA8D7A9D39817EA713421F4AE03FA8120641193892A70BFECF5\ -83101635A432110D3DDE6339E3CC7ECC0AD91C026FCACE832DD3888A6FCA7BCE56C390\ -5A5AC8C7BC921DA675E4B62489B254EB34659D547D71165BC998983A81937BD251AEE1\ -2D985EC387D5376F5DCC5EF7EC530FBD6FD2AA7285EE1AF3335EA73163F0954F30402E\ -D7B374EE84A97B1849B0674B0DA0A2050BD79B71ABB1559F3A9CFDB8557DED7BC90CF2\ -09E8A847E9C226140845B7D03842162E7DA5DD16326CB1F71A248D841FE9076A09911F\ -2F4F5E3EA44EA8DE40332BF00406990BCCF61C322A03C456EF3A98B341E0BDBC1088CE\ -683E78510E76B72C2BCC1EE9AEDD80FFF18ABFC5923B2F36B581C25114AB2DF9F6C2B1\ -9481703FD19E313DCD7ACE15FA11B27D25BCE5388C180A7E21167FB87750599E1ED7C7\ -50F4A844E1DC2270C62D19671CF8F4C25B81E366B09FC850AE642136D204A9160AEECE\ -575B57378AA439E9DD46DC990288CD54BAA35EEE1C02456CD39458A6F1CBF012DCEDF4\ -27CCF3F3F53645658FC49C9C9D7F2856DB571D92B967AB5845514E0054DDB49099F5DD\ -04A6F6F5C5CE642276834B932881AEB648D1F25E9223971F56E249EF40CF7D80F22621\ -CDD0260E9E7D23746960ADB52CF2987584FB1DE95A69A39E5CB12B76E0F5C1A0529C0C\ -065D2E35720810F7C7983180B9A9EA0E00C11B79DC3D"); +C6579F8646180EED0DC1F02E0DDD2B43EABB3F702D79D9928E2CDA5E1D42DF5D9ED777\ +3F80B1F8D9B0DB7D4D00F55647640D70768F63D3CED56A39C681D08D6191F318BB79DC\ +969B470A7364D53335C8318EF35E39D5DF706AB6F2393C6DD2128C142DBAB1806EB35E\ +26C908F0A48419313D2D0F33DD430655DBFEC722899EC21C238E8DB7003430BBC39BAD\ +990F9887F6B03E1344F537EC97389B78DBC656718ACD7B0FDC13DD24534F417BC7A18F\ +077A0C4227354CEA19670331B6CAA3DFC17BBA7E70C14510D9EB3B63F3014994EC87BD\ +23E868C0AE6E9EC55027577F62C0280B2D7DD1135001844923E5455C4566E066B3FDE9\ +68C6BC4DC672F229FCE366440403D7A4F4A8BFBA5679B7D0844BA1231277D13A77C9E2\ +B5A1CB138C1B7AB5B4D4832448723A3DE70ED2E86D5FC5174F949A02DE8E404304BEB9\ +5F9BF40F3AA3CA15622D2776294BE7E19233406FF563CB8C25A1CB5AADBC1899DA3F2A\ +E38533931FE032EE3232C2CD4F219FADF95B91635C0762A476A4DE5013F4384093F0FB\ +715028D97F93B2E6F057B99EE344D83ADF2686FD5C9C793928BEF3182E568C4339C36C\ +744C8E9CA7D4B9A16AA039CBF6F38CC97B12D87644E94C9DBD6BC93A93A03ED61ECC58\ +74586E3A310E958F858735E30019D345C62E5127B80652C8A970A14B31F03B3A157CD5"); mpi_fromstr(sk.e, "0x\ -DD4856B4EE3D099A8604AE392D8EFEC094CDF01546A28BE87CB484F999E8E75CDFCD01\ -D04D455A6A9254C60BD28C0B03611FC3E751CC27EF768C0B401C4FD2B27C092834A6F2\ -49A145C4EDC47A3B3D363EC352462C945334D160AF9AA72202862912493AC6190AA3A6\ -149D4D8B9996BA7927D3D0D2AD00D30FD630CF464E6CAF9CF49355B9A70E05DB7AE915\ -F9F602772F8D11E5FCDFC7709210F248052615967090CC1F43D410C83724AA5912B2F0\ -52E6B39449A89A97C79C92DC8CB8DEEFCF248C1E1D2FC5BFE85165ECA31839CAA9CEB3\ -3A92EBDC0EB3BAC0F810938BB173C7DA21DCBB2220D44CBA0FD40A2C868FC93AC5243E\ -C137C27B0A76D65634EBB3"); +F74D78E382FC19B064411C6C20E0FDB2985F843007A54C7D8400BB459468624126E7D1\ +75F397E55C57AF25858EAE2D2952FB7998C119A6103606733EB5E1D27FCA1FACF14ADE\ +94101D383D1B25DA511805569BC344EAD384EDBF3F3A541B34887FE199D99D7F62E6E9\ +D516F88D6F5AD3E020DF04D402A02CC628A0064362FE8516CF7CD6040E9521407AB90E\ +E6B5AFFF9EA9EBB16A7D3407CE81FD3844F519880556AB94AB349C1F3BBB6FDB4C4B37\ +7FE4C091EBDC2C3A1BD3AA56382D8D80E7742B5C751008FD6ECDD2EC3B2E3B6C566F69\ +8ED672000B403766DD63C3ACBDE16A14FB02E83A2EB6AA018BFC0020401E790DEE24E9"); mpi_fromstr(sk.d, "0x\ -7C8A6FA1199D99DCA45E9BDF567CA49D02B237340D7E999150BC4883AE29DEC5158521\ -B338F35DC883792356BDDBB3C8B3030A6DD4C6522599A3254E751F9BA1CB1061C5633C\ -81BBFACF6FCD64502614102DFED3F3FA284066C342D5E00953B415915331E30812E5FB\ -CD6680ADCCDEE40B8376A3A225F2E160EA59C7566804526D73BB660A648A3EF9802313\ -B2F841E8458B2AAACE7AACF31083E8F3F630298138393BC88BBD7D4AA4334949651D25\ -365B10DBF4A4A08E20A6CC74BFDD37C1C38E2ADC2A283DF06590DF06B46F67F6ACA67F\ -AC464C795261659A2F9558802D0BBAA05FD1E1AF2CDC70654723DF7EFAEA148B8CDBEB\ -C89EA2320AB9BBB1BC4311475DF3D91446F02EF192368DFEBAC598CCFD4407DEC58FDC\ -1A94CCDD6E5FBA9C52164ACEA8AEE633E557BCCEACB7A1AF656C379482D784A120A725\ -32F9B2B35173D505F21D5AD4CB9511BC836DC923730B70291B70290A216CA3B21CFF79\ -E895C35F4F7AF80E1BD9ED2773BD26919A76E4298D169160593E0335BE2A2A2D2E8516\ -948F657E1B1260E18808A9D463C108535FB60B3B28F711C81E5DE24F40214134A53CE5\ -9A952C8970A1D771EBEFFA2F4359DCF157995B3F1950DE3C6EC41B7FF837148F55F323\ -372AF3F20CE8B8038E750C23D8F5041FA951327859B0E47483F0A47103EF808C72C251\ -006FA526245291C8C84C12D2EF63FB2301EA3EEDA42B"); +698DA05DA25B230211EEF0CBA12083A1457B749A11937AC9993859F69A3BF38D575E51\ +66AF2EC88D77F1DF04E68AEA358EACF7659FD4722A4F5A1C8BA7676DA97A9FBA754511\ +52F8F68887D3451A9CCFFFE9EB80979786E37495B17687A6212F77FA616E4C0CD8A8EB\ +7AEB88EA6CCABB7F3E854FB94B35394A09F95F0D6F997947E865CC0606F437C30FE8C4\ +8D96FBF5E2F52807BC9E9ED7BBEB23D5C45EDDCD16FE2BF410A9A1E5EF879E71C0D41F\ +AE270C0C5D442860103F8C3944E802F33DB38432F11F763A7AF593656108E4A98A44A8\ +549913CE5DCEC1A6500F280E3190991B2B938561CFACD8BC5183AAC9A4914BFE52C3BE\ +39BB83688E1DE52479107EF8E087DCDB409432FC954C6349407E81DDFB11AE92BABB32\ +A31868597958C9C76E0B4156F380955F0E09C1F3B98BB4CDD59E1B5C7D8CC2AA7491B0\ +D319D219CF459A527CE1AA2729DEC53269653BF0ED3E0253F4451168437E3B069E4835\ +0CA4C3EC82134E87135624C768D1330B0D70C6E447FD9945BF06FCB91AA334C0FD8EEF\ +1ADBC15928B3DB62077B537F7E9F468CC95CD5AAFEAE1F760A863B48D07B163F670E2E\ +5B550BB3E960230BA9FDAED9903AE2E669A7F3C4D1F1E25B8E8EDB8CC6E6FD2164E66F\ +4E64ED77BEF1EC9E6CEA5624FD84C0680248746DC1C8187145F3CD2411659DAEAD11D"); mpi_fromstr(sk.p, "0x\ -E236732452039C14EC1D3B8095BDDCFB7625CE27B1EA5394CF4ED09D3CEECAA4FC0BF6\ -2F7CE975E0C8929CE84B0259D773EA038396479BF15DA065BA70E549B248D77B4B23ED\ -A267308510DBEE2FD44E35D880EE7CFB81E0646AA8630165BD8988C3A8776D9E704C20\ -AA25CA0A3C32F27F592D5FD363B04DD57D8C61FFDCDFCCC59E2913DE0EE47769180340\ -E1EA5A803AA2301A010FF553A380F002601F0853FCACDB82D76FE2FACBCD6E5F294439\ -0799EA5AE9D7880D4E1D4AE146DC1D4E8495B9DD30E57E883923C5FC26682B7142D35C\ -D8A0FC561FE725A6CF419B15341F40FE0C31132CBD81DD8E50697BD1EBFFA16B522E16\ -F5B49A03B707218C7DA60B"); +CDD6F7673A501FB24C44D56CA1D434F6CB3334E193E02F8E906241906BCB7412DD2159\ +825B24C22002F373E647C2DA62A854F3841C00FD5985D03227CA9B54A69380BA9D63BE\ +738BDF9E65C247E43E1220EEDD9281DCA78B32A4E1B786B7697ED0C3195D5AF2990881\ +B11D6FC9EC9F940067B2DEA2A516FAA5F269C98F0B67628A6D2708515A4A58041AA17A\ +93E4C4DD95C85BC38351DDA1DCF3DFD91C505B22383132649CF9F9233852C7207075BC\ +F43C71038F043F1EC53E9787FB051B7927D020903233C16897B993C8089D8464451F08\ +6E756CF20E46CE6ED4A6AC5C327A0AAFBECBAAFD177969E7C952C76A4F4E7C85BF7F63"); mpi_fromstr(sk.q, "0x\ -E830482A3C4F5C3A7E59C10FF8BA760DB1C6D55880B796FFDA4A82E0B60E974E81D04B\ -2A4AD417823EBFB4E8EFB13782943562B19B6C4A680E3BA0C8E37B5023470F4F1AC1F8\ -A0B10672EF75CD58BCD45E6B14503B8A6A70AFE79F6201AF56E7364A1C742BE1453FD2\ -24FDC9D66522EAF4466A084BCB9E46D455A2946E94CBF028770F38D0B741C2CC59308F\ -71D8C2B4B9C928E0AE8D68DEB48A3E9EFD84A10301EBD55F8221CA32FC567B306B2A8E\ -116350AFB995859FDF4378C5CFD06901494E8CFA5D8FAC564D6531FA8A2E4761F5EFBA\ -F78750B6F4662BE9EA4C2FAD67AF73EEB36B41FC15CB678810C19A51DF23555695C4C1\ -546F3FACA39CAA7BB8DBD7"); +F6ACF0790A250802C8D45DAC549CDBEF7806D5877A5DF0069136A458FAC4F0B0858060\ +A873DA6355A965A064A0BC1BBB874872CD7ED89674AD407533041E74BCA317EC73597D\ +335115523F61A05071E5ED81EE2A05331F65D4DC7A25AD7938B124CF03F49154B6693F\ +B0B598B33ABDEF85C599A57A9B7347EAFF82638E1CBC28FCDFFF1FF04A18C2DBF39383\ +95C2F8D1782B43D3A25EF7633B5DDAC89EFD3BAA64D976425A0891E00B876E9DE9FE4B\ +6492B0EA8DFC7C8DEEC61721356EC816295B1BD9CD9DA3E30D2D90DC9CB3987F4BE042\ +104900E036F3044A016749EF910CCFB9F377A90849B4CCCF4471A74E67EF6C814C9467"); mpi_fromstr(sk.u, "0x\ -846232322775C1CD7D5569DC59E2F3E61A885AE2E9C4A4F8CB3ACBE8C3A5441E5FE348\ -A2A8AC9C2998FBF282222BF508AA1ECF66A76AEDD2D9C97028BFD3F6CA0542E38A5312\ -603C70B95650CE73F80FDD729988FBDB5595A5BF8A007EA34E54994A697906CE56354C\ -E00DF10EB711DEC274A62494E3D350D88736CF67A477FB600AC9F1D6580727585092BF\ -5EBC092CC4D6CF75769051033A1197103BE269942F372168A53771746FBA18ED6972D5\ -0B935A9B1D6B5B3DD50CD89A27FE93C10924E9103FACF7B4C5724A046C3D3B50CC1C78\ -5F5C8E00DBE1D6561F120F5294C170914BC10F978ED4356EED67A9F3A60D70AFE540FC\ -5373CBAE3D0A7FD1C87273"); +854B89ED10F52258D00D6B3FA7F1FD22752804668F51FF7806DB82E22CB8B3AA8448D9\ +B8E9DB14D31A36AEC2BCFA89E341B7334D494E97ED8051244136192233332C4612D963\ +E7B6AF2535FDB7FE97E28DDFEBDFB3E1AFC29D05DBDF37106A817D3AB1864C7F7F2479\ +82897EDA6A92BED47D9C68305CD170C7301ACEB05F8A6382E73CC7614B2D8D758669B3\ +A99AB64114809254B0BE21F40341A5B48B9B032603B14875B87EB5E16603FD16552E14\ +6A0FC6964958DFC25AA9FFCCD1ED1F4DEAF9FBAA0D7357F5FF0803FEB9BA78E74AC6B3\ +070F417CEC6CFC7A3CF1E305FC7B76B7ED71893999AF797B2EBDE41FE90F076CCEDBFB"); // copy the public key components pk.n = mpi_copy( sk.n ); diff -uNr a/smg_comms/manifest b/smg_comms/manifest --- a/smg_comms/manifest 1d5b032f775b2b59d4bcbafdde81d65efb3e11925c30962717565cd0cb2c2218434dae770c470dc0a11b70f70b4cd78d37a3534741cfccb2e002cf4ed4e94008 +++ b/smg_comms/manifest 094d9668c13448f4869ab21bf0779d36675d26fa4648585bd73e9a661aa0f936dd440d9b2dd523d8d363c143fc4f6f9b4bbb20f4f7f7c05067b4f3992d3b7461 @@ -2,3 +2,4 @@ 546000 smg_comms_raw_types diana_coman Part of layer 0 - raw types for the updated version of the protocol containing only two types of packets: 1470 octets RSA packet and 1472 octets Serpent packet. 546152 smg_comms_packing_serpent diana_coman Packing/Unpacking Serpent messages <-> Serpent packets. Includes Serpent implementation. 547275 smg_comms_c_wrappers diana_coman C wrappers for RSA and MPI methods that are needed by SMG Comms (so that they can be called from Ada using only arrays of octets as inputs/outputs). +547983 smg_comms_rsa_oaep diana_coman RSA with OAEP from ADA using the c_wrappers for RSA only. It includes reading from FG in Ada and repeat of OAEP until first octet is < first octet of key's modulus (i.e. without going through MPI for comparison). diff -uNr a/smg_comms/restrict.adc b/smg_comms/restrict.adc --- a/smg_comms/restrict.adc 52ae9657ad5abadac6412597e48d26257703f293eb9348353097eeb9f2b00934fc862b075776b751b68e0423cbf452fbd1f3a9db0fb99c93e6d9f551114b33d7 +++ b/smg_comms/restrict.adc 8d73d5adc05be61c685c3f7123733fa7f032043684d5703dda4ae9092d4de5513226538bcf7256a9926db2f860ce5acc8c4b2a5739f12d88c0f47436c6325674 @@ -26,7 +26,7 @@ --pragma Restrictions(No_Floating_Point); pragma Restrictions(No_Implementation_Aspect_Specifications); pragma Restrictions(No_Implementation_Units); -pragma Restrictions(No_Implicit_Conditionals); +--pragma Restrictions(No_Implicit_Conditionals); pragma Restrictions(No_Implicit_Dynamic_Code); pragma Restrictions(No_Implicit_Heap_Allocations); pragma Restrictions(No_Implicit_Protected_Object_Allocations); diff -uNr a/smg_comms/rsa/tests/smg_rsa_tests.gpr b/smg_comms/rsa/tests/smg_rsa_tests.gpr --- a/smg_comms/rsa/tests/smg_rsa_tests.gpr 658150d9cc3ff5f1d4a6d134c57d9ea6740be6aef571ef9c2bd553a3e4931a541ccf755bf51dc5349a4dbaecf04dc11e0d4faff4d4745e322cf22231241570f5 +++ b/smg_comms/rsa/tests/smg_rsa_tests.gpr 7d578bdf06f017dcdbdd1da840952193ca7ee282c424259c3c8b299a36fb786b568177e55d5821fa542d39ca89f019f3e0f2fa43bfbeb48ce73d067fe67367b4 @@ -1,7 +1,7 @@ -- Tests for SMG_RSA (part of EuCrypt) -- S.MG, 2018 -with "../smg_rsa.gpr"; +with "../rsa.gpr"; project SMG_RSA_Tests is for Languages use("C"); diff -uNr a/smg_comms/rsa/tests/tests.c b/smg_comms/rsa/tests/tests.c --- a/smg_comms/rsa/tests/tests.c 89b1c405d92e249341bdc0bddc5a98d8ae8dd0349e04a165063d938f01df557a057be544c51b0efb6d72d505f1424a1aa3a6d7957e83f229711677240123e2fd +++ b/smg_comms/rsa/tests/tests.c 4835ebbc34c00a3a78a2a4ee13c9f553697525a2a21cb137e629d65d8b7e70a7dd1283f395a2c4590024e522c82d1dc027bbcbbb26c27a7d844b4a1fbd6f2941 @@ -409,152 +409,6 @@ mpi_free(sk.u); } -void test_oaep_encr_decr( int nruns ) { - /* a set of RSA keys previously generated with eucrypt */ - RSA_public_key pk; - pk.n = mpi_alloc(0); - pk.e = mpi_alloc(0); - - RSA_secret_key sk; - sk.n = mpi_alloc(0); - sk.e = mpi_alloc(0); - sk.d = mpi_alloc(0); - sk.p = mpi_alloc(0); - sk.q = mpi_alloc(0); - sk.u = mpi_alloc(0); - - mpi_fromstr(sk.n, "0x\ -CD2C025323BEA46FFF2FA8D7A9D39817EA713421F4AE03FA8120641193892A70BFECF5\ -83101635A432110D3DDE6339E3CC7ECC0AD91C026FCACE832DD3888A6FCA7BCE56C390\ -5A5AC8C7BC921DA675E4B62489B254EB34659D547D71165BC998983A81937BD251AEE1\ -2D985EC387D5376F5DCC5EF7EC530FBD6FD2AA7285EE1AF3335EA73163F0954F30402E\ -D7B374EE84A97B1849B0674B0DA0A2050BD79B71ABB1559F3A9CFDB8557DED7BC90CF2\ -09E8A847E9C226140845B7D03842162E7DA5DD16326CB1F71A248D841FE9076A09911F\ -2F4F5E3EA44EA8DE40332BF00406990BCCF61C322A03C456EF3A98B341E0BDBC1088CE\ -683E78510E76B72C2BCC1EE9AEDD80FFF18ABFC5923B2F36B581C25114AB2DF9F6C2B1\ -9481703FD19E313DCD7ACE15FA11B27D25BCE5388C180A7E21167FB87750599E1ED7C7\ -50F4A844E1DC2270C62D19671CF8F4C25B81E366B09FC850AE642136D204A9160AEECE\ -575B57378AA439E9DD46DC990288CD54BAA35EEE1C02456CD39458A6F1CBF012DCEDF4\ -27CCF3F3F53645658FC49C9C9D7F2856DB571D92B967AB5845514E0054DDB49099F5DD\ -04A6F6F5C5CE642276834B932881AEB648D1F25E9223971F56E249EF40CF7D80F22621\ -CDD0260E9E7D23746960ADB52CF2987584FB1DE95A69A39E5CB12B76E0F5C1A0529C0C\ -065D2E35720810F7C7983180B9A9EA0E00C11B79DC3D"); - - mpi_fromstr(sk.e, "0x\ -DD4856B4EE3D099A8604AE392D8EFEC094CDF01546A28BE87CB484F999E8E75CDFCD01\ -D04D455A6A9254C60BD28C0B03611FC3E751CC27EF768C0B401C4FD2B27C092834A6F2\ -49A145C4EDC47A3B3D363EC352462C945334D160AF9AA72202862912493AC6190AA3A6\ -149D4D8B9996BA7927D3D0D2AD00D30FD630CF464E6CAF9CF49355B9A70E05DB7AE915\ -F9F602772F8D11E5FCDFC7709210F248052615967090CC1F43D410C83724AA5912B2F0\ -52E6B39449A89A97C79C92DC8CB8DEEFCF248C1E1D2FC5BFE85165ECA31839CAA9CEB3\ -3A92EBDC0EB3BAC0F810938BB173C7DA21DCBB2220D44CBA0FD40A2C868FC93AC5243E\ -C137C27B0A76D65634EBB3"); - - mpi_fromstr(sk.d, "0x\ -7C8A6FA1199D99DCA45E9BDF567CA49D02B237340D7E999150BC4883AE29DEC5158521\ -B338F35DC883792356BDDBB3C8B3030A6DD4C6522599A3254E751F9BA1CB1061C5633C\ -81BBFACF6FCD64502614102DFED3F3FA284066C342D5E00953B415915331E30812E5FB\ -CD6680ADCCDEE40B8376A3A225F2E160EA59C7566804526D73BB660A648A3EF9802313\ -B2F841E8458B2AAACE7AACF31083E8F3F630298138393BC88BBD7D4AA4334949651D25\ -365B10DBF4A4A08E20A6CC74BFDD37C1C38E2ADC2A283DF06590DF06B46F67F6ACA67F\ -AC464C795261659A2F9558802D0BBAA05FD1E1AF2CDC70654723DF7EFAEA148B8CDBEB\ -C89EA2320AB9BBB1BC4311475DF3D91446F02EF192368DFEBAC598CCFD4407DEC58FDC\ -1A94CCDD6E5FBA9C52164ACEA8AEE633E557BCCEACB7A1AF656C379482D784A120A725\ -32F9B2B35173D505F21D5AD4CB9511BC836DC923730B70291B70290A216CA3B21CFF79\ -E895C35F4F7AF80E1BD9ED2773BD26919A76E4298D169160593E0335BE2A2A2D2E8516\ -948F657E1B1260E18808A9D463C108535FB60B3B28F711C81E5DE24F40214134A53CE5\ -9A952C8970A1D771EBEFFA2F4359DCF157995B3F1950DE3C6EC41B7FF837148F55F323\ -372AF3F20CE8B8038E750C23D8F5041FA951327859B0E47483F0A47103EF808C72C251\ -006FA526245291C8C84C12D2EF63FB2301EA3EEDA42B"); - - mpi_fromstr(sk.p, "0x\ -E236732452039C14EC1D3B8095BDDCFB7625CE27B1EA5394CF4ED09D3CEECAA4FC0BF6\ -2F7CE975E0C8929CE84B0259D773EA038396479BF15DA065BA70E549B248D77B4B23ED\ -A267308510DBEE2FD44E35D880EE7CFB81E0646AA8630165BD8988C3A8776D9E704C20\ -AA25CA0A3C32F27F592D5FD363B04DD57D8C61FFDCDFCCC59E2913DE0EE47769180340\ -E1EA5A803AA2301A010FF553A380F002601F0853FCACDB82D76FE2FACBCD6E5F294439\ -0799EA5AE9D7880D4E1D4AE146DC1D4E8495B9DD30E57E883923C5FC26682B7142D35C\ -D8A0FC561FE725A6CF419B15341F40FE0C31132CBD81DD8E50697BD1EBFFA16B522E16\ -F5B49A03B707218C7DA60B"); - - mpi_fromstr(sk.q, "0x\ -E830482A3C4F5C3A7E59C10FF8BA760DB1C6D55880B796FFDA4A82E0B60E974E81D04B\ -2A4AD417823EBFB4E8EFB13782943562B19B6C4A680E3BA0C8E37B5023470F4F1AC1F8\ -A0B10672EF75CD58BCD45E6B14503B8A6A70AFE79F6201AF56E7364A1C742BE1453FD2\ -24FDC9D66522EAF4466A084BCB9E46D455A2946E94CBF028770F38D0B741C2CC59308F\ -71D8C2B4B9C928E0AE8D68DEB48A3E9EFD84A10301EBD55F8221CA32FC567B306B2A8E\ -116350AFB995859FDF4378C5CFD06901494E8CFA5D8FAC564D6531FA8A2E4761F5EFBA\ -F78750B6F4662BE9EA4C2FAD67AF73EEB36B41FC15CB678810C19A51DF23555695C4C1\ -546F3FACA39CAA7BB8DBD7"); - - mpi_fromstr(sk.u, "0x\ -846232322775C1CD7D5569DC59E2F3E61A885AE2E9C4A4F8CB3ACBE8C3A5441E5FE348\ -A2A8AC9C2998FBF282222BF508AA1ECF66A76AEDD2D9C97028BFD3F6CA0542E38A5312\ -603C70B95650CE73F80FDD729988FBDB5595A5BF8A007EA34E54994A697906CE56354C\ -E00DF10EB711DEC274A62494E3D350D88736CF67A477FB600AC9F1D6580727585092BF\ -5EBC092CC4D6CF75769051033A1197103BE269942F372168A53771746FBA18ED6972D5\ -0B935A9B1D6B5B3DD50CD89A27FE93C10924E9103FACF7B4C5724A046C3D3B50CC1C78\ -5F5C8E00DBE1D6561F120F5294C170914BC10F978ED4356EED67A9F3A60D70AFE540FC\ -5373CBAE3D0A7FD1C87273"); - - /* copy the public key components */ - pk.n = mpi_copy( sk.n ); - pk.e = mpi_copy( sk.e ); - - /* some plain text message */ - MPI msg = mpi_alloc(0); - mpi_fromstr(msg, "0x\ -5B6A8A0ACF4F4DB3F82EAC2D20255E4DF3E4B7C799603210766F26EF87C8980E737579\ -EC08E6505A51D19654C26D806BAF1B62F9C032E0B13D02AF99F7313BFCFD68DA46836E\ -CA529D7360948550F982C6476C054A97FD01635AB44BFBDBE2A90BE06F7984AC8534C3\ -28097EF92F6E78CAE0CB97"); - - /* actual testing */ - printf("TEST verify oaep_encr_decr on message: \n"); - mpi_print( stdout, msg, 1); - printf("\n"); - - int nlimbs_n = mpi_nlimb_hint_from_nbytes( KEY_LENGTH_OCTETS); - MPI encr = mpi_alloc( nlimbs_n ); - MPI decr = mpi_alloc( nlimbs_n ); - int success; - - adainit(); - rsa_oaep_encrypt( encr, msg, &pk ); - rsa_oaep_decrypt( decr, encr, &sk, &success ); - - if (success <= 0 || - mpi_cmp(encr, msg) == 0 || - mpi_cmp(msg, decr) != 0) - printf("FAILED: success flag is %d\n", success); - else - printf("PASSED\n"); - - /* attempt to decrypt corrupted block */ - mpi_clear( decr ); - rsa_oaep_decrypt( decr, pk.n, &sk, &success); - if (success > 0) - printf("FAILED: attempt to decrypt non-/corrupted oaep block\n"); - else - printf("PASSED: attempt to decrypt non-/corrupted oaep block\n"); - adafinal(); - - /* clean up */ - mpi_free( sk.n ); - mpi_free( sk.e ); - mpi_free( sk.d ); - mpi_free( sk.p ); - mpi_free( sk.q ); - mpi_free( sk.u ); - - mpi_free( pk.n ); - mpi_free( pk.e ); - - mpi_free( msg ); - mpi_free( encr ); - mpi_free( decr ); -} - void test_mpi_buffer() { unsigned int noctets = 10; int nlimbs = mpi_nlimb_hint_from_nbytes( noctets ); @@ -720,21 +574,18 @@ time_rsa_gen(nruns); break; case 9: - test_oaep_encr_decr(nruns); - break; - case 10: test_mpi_buffer(); break; - case 11: + case 10: test_dirty_float_rng(nruns); break; - case 12: + case 11: test_ieee_float_rng(nruns); break; - case 13: + case 12: test_uint32_rng(nruns); break; - case 14: + case 13: test_uint64_rng(nruns); break; default: @@ -749,12 +600,11 @@ writes to keys.asc and check_keys.asc\n"); printf("7 for testing rsa exponentiation (fixed data)\n"); printf("8 for timing rsa key pair generator\n"); - printf("9 for oaep encrypt/decrypt\n"); - printf("10 for testing mpi_set/get_buffer\n"); - printf("11 for testing smg_rng dirty float\n"); - printf("12 for testing smg_rng ieee 745/1985 float\n"); - printf("13 for testing smg_rng uint32 \n"); - printf("14 for testing smg_rng uint64 \n"); + printf("9 for testing mpi_set/get_buffer\n"); + printf("10 for testing smg_rng dirty float\n"); + printf("11 for testing smg_rng ieee 745/1985 float\n"); + printf("12 for testing smg_rng uint32 \n"); + printf("13 for testing smg_rng uint64 \n"); } return 0; diff -uNr a/smg_comms/src/keccak.adb b/smg_comms/src/keccak.adb --- a/smg_comms/src/keccak.adb false +++ b/smg_comms/src/keccak.adb 53945ea441af37b53c009c3b31826bb688cba5525176d55ed76b934fa34702a86e31041cf4d125fa9fc827c41c242a06e472a0ad2d80fb33dda9f9ab08260458 @@ -0,0 +1,271 @@ + -- S.MG, 2018 +with System; use System; -- for Bit_Order + +package body Keccak is + +-- public function, sponge + procedure Sponge( Input : in Bitstream; + Output : out Bitstream; + Block_Len : in Keccak_Rate := Default_Bitrate ) is + Internal : State := (others => (others => 0)); + begin + --absorb input into sponge in a loop on available blocks, including padding + declare + -- number of input blocks after padding (2 to block_len bits pad) + Padded_Blocks : constant Positive := 1 + (Input'Length + 1) / Block_Len; + Padded : Bitstream ( 1 .. Padded_Blocks * Block_Len ); + Block : Bitstream ( 1 .. Block_Len ); + begin + -- initialise Padded with 0 everywhere + Padded := ( others => 0 ); + -- copy and pad input with rule 10*1 + Padded( Padded'First .. Padded'First + Input'Length - 1 ) := Input; + Padded( Padded'First + Input'Length ) := 1; + Padded( Padded'Last ) := 1; + + -- loop through padded input and absorb block by block into sponge + -- padded input IS a multiple of blocks, so no stray bits left + for B in 0 .. Padded_Blocks - 1 loop + -- first get the current block to absorb + Block := Padded( Padded'First + B * Block_Len .. + Padded'First + (B+1) * Block_Len - 1 ); + AbsorbBlock( Block, Internal ); + -- scramble state with Keccak function + Internal := Keccak_Function( Internal ); + + end loop; -- end absorb loop for blocks + end; -- end absorb stage + + --squeeze required bits from sponge in a loop as needed + declare + -- full blocks per output + BPO : constant Natural := Output'Length / Block_Len; + -- stray bits per output + SPO : constant Natural := Output'Length mod Block_Len; + Block : Bitstream( 1 .. Block_Len ); + begin + -- squeeze block by block (if at least one full block is needed) + for I in 0 .. BPO - 1 loop + SqueezeBlock( Block, Internal ); + Output( Output'First + I * Block_Len .. + Output'First + (I + 1) * Block_Len -1) := Block; + + -- scramble state + Internal := Keccak_Function( Internal ); + end loop; -- end squeezing full blocks + + -- squeeze any partial block needed (stray bits) + if SPO > 0 then + SqueezeBlock( Block, Internal ); + Output( Output'Last - SPO + 1 .. Output'Last ) := + Block( Block'First .. Block'First + SPO - 1 ); + end if; -- end squeezing partial last block (stray bits) + + end; -- end squeeze stage + end Sponge; + + -- convert from a bitstream of ZWord size to an actual ZWord number + function BitsToWord( BWord: in Bitword ) return ZWord is + W : ZWord; + Bits: Bitword; + begin + -- just copy octets if machine is little endian + -- flip octets if machine is big endian + if Default_Bit_Order = Low_Order_First then + Bits := BWord; + else + Bits := FlipOctets( BWord ); + end if; + -- actual bits to word conversion + W := 0; + -- LSB bit order (inside octet) as per Keccak spec + for I in reverse Bitword'Range loop + W := Shift_Left( W, 1 ) + ZWord( Bits( I ) ); + end loop; + return W; + end BitsToWord; + + -- convert from a ZWord (lane of state) to a bitstream of ZWord size + function WordToBits( Word: in ZWord ) return Bitword is + Bits: Bitword := (others => 0); + W: ZWord; + begin + W := Word; + for I in Bitword'Range loop + Bits( I ) := Bit( W mod 2 ); + W := Shift_Right( W, 1 ); + end loop; + + -- flip octets if machine is big endian + if Default_Bit_Order = High_Order_First then + Bits := FlipOctets( Bits ); + end if; + + return Bits; + end WordToBits; + + -- flip given octets (i.e. groups of 8 bits) + function FlipOctets( BWord : in Bitword ) return Bitword is + Bits : Bitword; + begin + -- copy groups of 8 octets changing their order in the array + -- i.e. 1st octet in BWord becomes last octet in Bits and so on + for I in 0 .. ( Bitword'Length / 8 - 1 ) loop + Bits ( Bits'First + I * 8 .. Bits'First + I * 8 + 7 ) := + BWord( BWord'Last - I * 8 - 7 .. BWord'Last - I * 8); + end loop; + return Bits; + end FlipOctets; + +-- helper procedures for sponge absorb/squeeze + + -- NO scramble here, this will absorb ALL given block, make sure it fits! + procedure AbsorbBlock( Block: in Bitstream; S: in out State ) is + WPB: constant Natural := Block'Length / Z_Length; -- words per block + SBB: constant Natural := Block'Length mod Z_Length; -- stray bits + FromPos, ToPos : Natural; + X, Y : XYCoord; + Word : ZWord; + BWord : Bitword; + begin + -- xor current block into first Block'Length bits of state + -- a block can consist in more than one word + X := 0; + Y := 0; + for I in 0..WPB-1 loop + FromPos := Block'First + I * Z_Length; + ToPos := FromPos + Z_Length - 1; + Word := BitsToWord( Block( FromPos .. ToPos ) ); + S( X, Y ) := S( X, Y ) xor Word; + -- move on to next word in state + X := X + 1; + if X = 0 then + Y := Y + 1; + end if; + end loop; + -- absorb also any remaining bits from block + if SBB > 0 then + ToPos := Block'Last; + FromPos := ToPos - SBB + 1; + BWord := (others => 0); + BWord(Bitword'First .. Bitword'First + SBB - 1) := Block(FromPos..ToPos); + Word := BitsToWord( BWord ); + S( X, Y ) := S( X, Y ) xor Word; + end if; + end AbsorbBlock; + + --NO scramble here, this will squeeze Block'Length bits out of *same* state S + procedure SqueezeBlock( Block: out Bitstream; S: in State) is + X, Y : XYCoord; + BWord : Bitword; + FromPos : Natural; + Len : Natural; + begin + X := 0; + Y := 0; + FromPos := Block'First; + + while FromPos <= Block'Last loop + BWord := WordToBits( S(X, Y) ); + + X := X + 1; + if X = 0 then + Y := Y + 1; + end if; + + -- copy full word if it fits or + -- only as many bits as are still needed to fill the block + Len := Block'Last - FromPos + 1; + if Len > Z_Length then + Len := Z_Length; + end if; + + Block(FromPos..FromPos+Len-1) := BWord(BWord'First..BWord'First+Len-1); + FromPos := FromPos + Len; + end loop; + end SqueezeBlock; + + +-- private, internal transformations + function Theta(Input : in State) return State is + Output : State; + C : Plane; + W : ZWord; + begin + for X in XYCoord loop + C(X) := Input(X, 0); + for Y in 1..XYCoord'Last loop + C(X) := C(X) xor Input(X, Y); + end loop; + end loop; + + for X in XYCoord loop + W := C(X-1) xor Rotate_Left(C(X+1), 1); + for Y in XYCoord loop + Output(X,Y) := Input(X,Y) xor W; + end loop; + end loop; + + return Output; + end Theta; + + function Rho(Input : in State) return State is + Output : State; + X, Y, Old_Y : XYCoord; + begin + Output(0,0) := Input(0,0); + X := 1; + Y := 0; + + for T in 0..23 loop + Output(X, Y) := Rotate_Left(Input(X,Y), ((T+1)*(T+2)/2) mod Z_Length); + Old_Y := Y; + Y := 2*X + 3*Y; + X := Old_Y; + end loop; + return Output; + end rho; + + function Pi(Input : in State) return State is + Output: State; + begin + for X in XYCoord loop + for Y in XYCoord loop + Output(Y, 2*X + 3*Y) := Input(X, Y); + end loop; + end loop; + return Output; + end pi; + + function Chi(Input : in State) return State is + Output: State; + begin + for Y in XYCoord loop + for X in XYCoord loop + Output(X, Y) := Input(X, Y) xor + ( (not Input(X + 1, Y)) and Input(X + 2, Y) ); + end loop; + end loop; + return Output; + end chi; + + function Iota(Round_Const : in ZWord; Input : in State) return State is + Output: State; + begin + Output := Input; + Output(0,0) := Input(0,0) xor Round_Const; + return Output; + end iota; + + function Keccak_Function(Input: in State) return State is + Output: State; + begin + Output := Input; + for I in Round_Index loop + Output := Iota(RC(I), Chi(Pi(Rho(Theta(Output))))); + end loop; + + return Output; + end Keccak_Function; + +end Keccak; diff -uNr a/smg_comms/src/keccak.ads b/smg_comms/src/keccak.ads --- a/smg_comms/src/keccak.ads false +++ b/smg_comms/src/keccak.ads dc5cff0b04cfab46a536021938afcd0649409872771b21800d10175028df61751aa6e919d9ebd3f07c16327a467510fcf48f02ba5ccb52cf5e989dbf6c5fed0b @@ -0,0 +1,135 @@ + -- S.MG implementation of Keccak-f permutations + + -- (Based on The Keccak Reference, Version 3.0, January 14, 2011, by + -- Guido Bertoni, Joan Daemen, Michael Peeters and Gilles Van Assche) + + -- S.MG, 2018 + +package Keccak is + pragma Pure(Keccak); --stateless, no side effects -> can cache calls + + --knobs (can change as per keccak design but fixed here for S.MG purposes)-- + Keccak_L: constant := 6; --gives keccak z (word) dimension of 2^6=64 and + --therefore keccak function 1600 with current + --constants (5*5*2^6) + + Default_Bitrate: constant := 1344; --max bits the sponge can eat/spit without + --needing to scramble the state + + --constants: dimensions of keccak state and number of rounds + XY_Length: constant := 5; + Z_Length: constant := 2**Keccak_L; + Width: constant := XY_Length * XY_Length * Z_Length; + N_Rounds: constant := 12 + 2*Keccak_L; + + --types + type XYCoord is mod XY_Length; + type ZCoord is mod Z_Length; + type Round_Index is mod N_Rounds; + + type ZWord is mod 2**Z_Length; --"lane" in keccak ref + type Plane is array(XYCoord) of ZWord; --a "horizontal slice" of keccak state + type State is array(XYCoord, XYCoord) of ZWord; --the full keccak state + + type Round_Constants is array(Round_Index) of ZWord; --magic keccak constants + + -- rate can be chosen by caller at each call, between 1 and width of state + -- higher rate means sponge "eats" more bits at a time but has fewer bits in + -- the "secret" part of the state (i.e. lower capacity) + subtype Keccak_Rate is Positive range 1..Width; -- capacity = width - rate + + type Bit is mod 2; + type Bitstream is array( Natural range <> ) of Bit; -- any length; message + subtype Bitword is Bitstream( 0..Z_Length - 1 ); -- bits of one state "word" + + -- type conversions + function BitsToWord( BWord : in Bitword ) return ZWord; + function WordToBits( Word : in ZWord ) return Bitword; + + -- flip input octets (i.e. groups of 8 bits) + function FlipOctets( BWord : in Bitword ) return Bitword; + + -- public function, the sponge itself + -- Keccak sponge structure using Keccak_Function, Pad and a given bitrate; + -- Input - the stream of bits to hash (the message) + -- Output - a bitstream of desired size for holding output + -- Block_Len - the bitrate to use; this is effectively the block length + -- for splitting Input AND squeezing output between scrambles + procedure Sponge(Input : in Bitstream; + Output : out Bitstream; + Block_Len : in Keccak_Rate := Default_Bitrate ); + +private + -- these are internals of the keccak implementation, not meant to be directly + -- accessed/used + + -- this will squeeze Block'Length bits out of state S + -- NO scramble of state in here! + -- NB: make SURE that Block'Length is the correct bitrate for this sponge + -- specifically: Block'Length should be a correct bitrate aka LESS than Width + procedure SqueezeBlock( Block: out Bitstream; S: in State); + + -- This absorbs into sponge the given block, modifying the state accordingly + -- NO scramble of state in here so make sure the whole Block fits in state! + -- NB: make SURE that Block'Length is *the correct bitrate* for this sponge + -- specifically: Block'Length should be a correct bitrate aka LESS than Width + procedure AbsorbBlock( Block: in Bitstream; S: in out State ); + + --Keccak magic numbers + RC : constant Round_Constants := + ( + 16#0000_0000_0000_0001#, + 16#0000_0000_0000_8082#, + 16#8000_0000_0000_808A#, + 16#8000_0000_8000_8000#, + 16#0000_0000_0000_808B#, + 16#0000_0000_8000_0001#, + 16#8000_0000_8000_8081#, + 16#8000_0000_0000_8009#, + 16#0000_0000_0000_008A#, + 16#0000_0000_0000_0088#, + 16#0000_0000_8000_8009#, + 16#0000_0000_8000_000A#, + 16#0000_0000_8000_808B#, + 16#8000_0000_0000_008B#, + 16#8000_0000_0000_8089#, + 16#8000_0000_0000_8003#, + 16#8000_0000_0000_8002#, + 16#8000_0000_0000_0080#, + 16#0000_0000_0000_800A#, + 16#8000_0000_8000_000A#, + 16#8000_0000_8000_8081#, + 16#8000_0000_0000_8080#, + 16#0000_0000_8000_0001#, + 16#8000_0000_8000_8008# + ); + + --gnat-specific methods to have bit-ops for modular types + function Rotate_Left( Value : ZWord; + Amount : Natural) + return ZWord; + pragma Import(Intrinsic, Rotate_Left); + + function Shift_Right( Value : ZWord; + Amount : Natural) + return ZWord; + pragma Import(Intrinsic, Shift_Right); + + function Shift_Left( Value : ZWord; + Amount : Natural) + return ZWord; + pragma Import(Intrinsic, Shift_Left); + + --Keccak transformations of the internal state + function Theta ( Input : in State) return State; + function Rho ( Input : in State) return State; + function Pi ( Input : in State) return State; + function Chi ( Input : in State) return State; + function Iota ( Round_Const : in ZWord; Input : in State) return State; + + --Keccak function with block width currently 1600 (Width constant above) + --this simply applies *all* keccak transformations in the correct order, + -- using the keccak magic numbers (round constants) as per keccak reference + function Keccak_Function(Input: in State) return State; + +end Keccak; diff -uNr a/smg_comms/src/oaep.adb b/smg_comms/src/oaep.adb --- a/smg_comms/src/oaep.adb false +++ b/smg_comms/src/oaep.adb 982b3d71f5ae114abc3a8a5c754e0f645d62694bedef479dec7d51ddc454ac23f19edf27526b2f1a5d91a73ee0111c2761c29551e5c6894d4844660e2981717c @@ -0,0 +1,176 @@ +-- S.MG, 2018 + +package body OAEP is + + -- padding & formatting of maximum MAX_LEN_MSG*8 bits of the given input + -- uses TMSR's OAEP schema: + -- 1.format M00 as: [random octet][sz1][sz2]"TMSR-RSA"[random]*Message + -- where sz1 and sz2 store the length of the message in bits + -- the random octets before message are padding to make OAEP_LENGTH_OCTETS + -- 2. R = OAEP_HALF_OCTETS random bits + -- 3. X = M00 xor hash(R) + -- 4. Y = R xor hash(X) + -- 5. Result is X || Y + -- NB: the Entropy parameter should be random octets from which this method + -- will use as many as required for the OAEP encryption of given Msg + -- NB: at MOST MAX_LEN_MSG octets of Msg! (Msg at most 1960 bits) + procedure OAEP_Encrypt( Msg : in Raw_Types.Octets; + Entropy : in OAEP_Block; + Output : out OAEP_Block) is + M00 : OAEP_HALF; + R : OAEP_HALF; + HashR : OAEP_HALF; + X : OAEP_HALF; + HashX : OAEP_HALF; + Y : OAEP_HALF; + MsgLen : Natural; + PadLen : Natural; + begin + -- calculate maximum length of msg and needed amount of padding + -- make sure also that only MAX_LEN_MSG octets at most are used from Msg + MsgLen := Msg'Length; -- real msg length + if MsgLen > MAX_LEN_MSG then + MsgLen := MAX_LEN_MSG; --only first MAX_LEN_MSG octets used + PadLen := 0; --no padding needed + else + PadLen := MAX_LEN_MSG - MsgLen; -- add padding as needed + end if; + + -- step 1: header and format to obtain M00 + -- first octet is random bits + M00( M00'First ) := Entropy( Entropy'First ); + + -- next 2 octets hold the used length of Msg (number of octets) + M00( M00'First + 2) := Unsigned_8( ( MsgLen * 8 ) mod 256 ); + M00( M00'First + 1) := Unsigned_8( ( (MsgLen * 8 ) / 256 ) mod 256 ); + + -- next 8 octets are reserved for later use, currently "TMSR-RSA" + M00( M00'First + 3 .. M00'First + 10 ) := TMSR; + + -- random bits for padding, if Msg is less than maximum length + for I in 1 .. PadLen loop + M00( M00'First + 10 + I ) := Entropy( Entropy'First + I ); + end loop; + + -- the message itself + M00( M00'Last - MsgLen + 1 .. M00'Last ) := + Msg( Msg'First .. Msg'First + MsgLen - 1 ); + + -- step 2: R = Raw_Types.OAEP_HALF_OCTETS random octets + -- can take LAST octets from given entropy as they are NOT used before + -- (even if original message was empty, padding uses at most half - 10 + -- while entropy has full block length) + R := Entropy( Entropy'Last - OAEP_HALF_OCTETS + 1 .. Entropy'Last ); + + -- step 3: X = M00 xor hash(R) + HashKeccak( R, HashR ); + X := XOR_Octets(M00, HashR); + + -- step 4: Y = R xor hash(X) + HashKeccak( X, HashX ); + Y := XOR_Octets(R, HashX); + + -- step 5: Output is X || Y + Output( Output'First .. Output'First + X'Length - 1 ) := X; + Output( Output'Last - Y'Length + 1 .. Output'Last ) := Y; + + end OAEP_Encrypt; + + procedure OAEP_Decrypt( Encr : in OAEP_Block; + Len : out Natural; + Output : out OAEP_HALF; + Success : out Boolean ) is + X, Y, M, R : OAEP_HALF; + HashX, HashR : OAEP_HALF; + LenOctets : Natural; + begin + -- step 1: separate X and Y + X := Encr( Encr'First .. Encr'First + X'Length - 1 ); + Y := Encr( Encr'Last - Y'Length + 1 .. Encr'Last ); + + -- step 2: R = Y xor hash(X) + HashKeccak( X, HashX ); + R := XOR_Octets(Y, HashX); + + -- step 3: M = X xor hash(R) + HashKeccak( R, HashR ); + M := XOR_Octets(X, HashR); + + -- step 4: extract length and message + Len := Natural(M( M'First + 1 )) * 256 + + Natural(M( M'First + 2 )); + LenOctets := Len / 8; + + if LenOctets > MAX_LEN_MSG or LenOctets < 0 then + Success := False; -- error, failed to retrieve message + else + Success := True; + Output( Output'First .. Output'First + LenOctets - 1 ) := + M( M'Last - LenOctets + 1 .. M'Last ); + end if; + + end OAEP_Decrypt; + +-- private, helper methods + procedure HashKeccak(Input : in Raw_Types.Octets; + Output : out Raw_Types.Octets; + Block_Len : in Keccak.Keccak_Rate := + Keccak.Default_Bitrate) is + BIn : Keccak.Bitstream( 0 .. Input'Length * 8 - 1 ); + BOut : Keccak.Bitstream( 0 .. Output'Length * 8 - 1 ); + begin + ToBitstream( Input, BIn ); + Keccak.Sponge( BIn, BOut, Block_Len ); + ToOctets( BOut, Output ); + end HashKeccak; + + function XOR_Octets(A : in OAEP_HALF; + B : in OAEP_HALF) + return OAEP_HALF is + R : OAEP_HALF; + begin + for I in R'Range loop + R(I) := A(I) xor B(I); + end loop; + return R; + end XOR_Octets; + + -- conversion between types + procedure ToOctets(B: in Keccak.Bitstream; O: out Raw_Types.Octets ) is + Pos : Natural; + begin + Pos := B'First; + for I in O'Range loop + O(I) := Unsigned_8( B( Pos ) ) + + Unsigned_8( B( Pos + 1 ) ) * 2 + + Unsigned_8( B( Pos + 2 ) ) * 4 + + Unsigned_8( B( Pos + 3 ) ) * 8 + + Unsigned_8( B( Pos + 4 ) ) * 16 + + Unsigned_8( B( Pos + 5 ) ) * 32 + + Unsigned_8( B( Pos + 6 ) ) * 64 + + Unsigned_8( B( Pos + 7 ) ) * 128; + Pos := Pos + 8; + end loop; + end ToOctets; + + procedure ToBitstream(O: in Raw_Types.Octets; B: out Keccak.Bitstream ) is + V : Unsigned_8; + Pos : Natural; + begin + Pos := B'First; + for I in O'Range loop + V := O( I ); + B( Pos ) := Keccak.Bit( V and 1 ); + B( Pos + 1 ) := Keccak.Bit( Shift_Right( V, 1 ) and 1 ); + B( Pos + 2 ) := Keccak.Bit( Shift_Right( V, 2 ) and 1 ); + B( Pos + 3 ) := Keccak.Bit( Shift_Right( V, 3 ) and 1 ); + B( Pos + 4 ) := Keccak.Bit( Shift_Right( V, 4 ) and 1 ); + B( Pos + 5 ) := Keccak.Bit( Shift_Right( V, 5 ) and 1 ); + B( Pos + 6 ) := Keccak.Bit( Shift_Right( V, 6 ) and 1 ); + B( Pos + 7 ) := Keccak.Bit( Shift_Right( V, 7 ) and 1 ); + + Pos := Pos + 8; + end loop; + end ToBitstream; + +end OAEP; diff -uNr a/smg_comms/src/oaep.ads b/smg_comms/src/oaep.ads --- a/smg_comms/src/oaep.ads false +++ b/smg_comms/src/oaep.ads c4d51b3d41ca323c78b1c7a591b002a59fc756a1d895041dd2d3ddf4f2f2fcb60714c65e6a338949d8ce2ac5ef2bcccb1365c97842e013849707cefa4e633a4b @@ -0,0 +1,87 @@ +-- Implementation of TMSR's OAEP with Keccak as hash function +-- NB: this uses Eulora's protocol constants (esp. RSA key length) and types. +-- +-- S.MG, 2018 + +with Keccak; -- Keccak is used as hash function +with Raw_Types; -- Eulora's protocol raw types and constant values + +with Interfaces; use Interfaces; -- for Unsigned_8 type and bit-level ops + +package OAEP is + pragma Pure( OAEP ); -- stateless, no side effects -> can cache calls + + -- constants for OAEP + OAEP_LENGTH_OCTETS : constant := Raw_Types.RSA_KEY_OCTETS; + OAEP_LENGTH_BITS : constant := OAEP_LENGTH_OCTETS * 8; + OAEP_HALF_OCTETS : constant := OAEP_LENGTH_OCTETS / 2; + TMSR_STR : constant String := "TMSR-RSA"; + -- "TMSR-RSA" as unsigned_8 values: + TMSR : constant Raw_Types.Octets := (84,77,83,82,45,82,83,65); + MAX_LEN_MSG : constant Natural := OAEP_HALF_OCTETS - + TMSR_STR'Length - 3; + + -- subtypes for OAEP encrypt/decrypt + subtype OAEP_Block is Raw_Types.Octets( 1 .. OAEP_LENGTH_OCTETS ); + subtype OAEP_HALF is Raw_Types.Octets( 1 .. OAEP_HALF_OCTETS ); + + -- padding & formatting of maximum MAX_LEN_MSG octets of the given input + -- uses TMSR's OAEP schema: + -- 1.format M00 as: [random octet][sz1][sz2]"TMSR-RSA"[random]*Message + -- where sz1 and sz2 store the length of the message in bits + -- the random octets before message are padding to make OAEP_LENGTH_OCTETS + -- 2. R = OAEP_HALF_OCTETS random bits + -- 3. X = M00 xor hash(R) + -- 4. Y = R xor hash(X) + -- 5. Result is X || Y + -- NB: the Entropy parameter should be random octets from which this method + -- will use as many as required for the OAEP encryption of given Msg + -- NB: at MOST MAX_LEN_MSG octets of Msg! (Msg at most MAX_LEN_MSG*8 bits!) + procedure OAEP_Encrypt( Msg : in Raw_Types.Octets; + Entropy : in OAEP_Block; + Output : out OAEP_Block); + + + -- This is the opposite of OAEP_Encrypt above. + -- @param Encr - an OAEP block previously obtained from OAEP_Encrypt + -- @param Len - this will hold the length of the obtained message (in bits!) + -- @param Output - the first Len octets of this are the recovered message + -- @param Success - set to TRUE if message was recovered, false otherwise + -- NB: when Success is FALSE, both Len and Output have undefined values + procedure OAEP_Decrypt( Encr : in OAEP_Block; + Len : out Natural; + Output : out OAEP_HALF; + Success : out Boolean); + +private + -- gnat-specific methods for bit-level operations + function Shift_Right( Value : Unsigned_8; + Amount : Natural ) + return Unsigned_8; + pragma Import(Intrinsic, Shift_Right); + + function Shift_Left( Value : Unsigned_8; + Amount : Natural ) + return Unsigned_8; + pragma Import(Intrinsic, Shift_Left); + + -- helper method: xor 2 half-oaep blocks + function XOR_Octets(A : in OAEP_HALF; + B : in OAEP_HALF) + return OAEP_HALF; + + -- conversions between bitstream and string + -- NB: caller has to ensure correct size of output parameter! no checks here. + procedure ToOctets ( B : in Keccak.Bitstream; + O : out Raw_Types.Octets ); + + procedure ToBitstream( O : in Raw_Types.Octets; + B : out Keccak.Bitstream ); + + -- wrapper for Sponge to use Octets for input/output + procedure HashKeccak( Input : in Raw_Types.Octets; + Output : out Raw_Types.Octets; + Block_Len : in Keccak.Keccak_Rate := + Keccak.Default_Bitrate); + +end OAEP; diff -uNr a/smg_comms/src/raw_types.ads b/smg_comms/src/raw_types.ads --- a/smg_comms/src/raw_types.ads 8b32dfa8a36c4cb27171b299d329919b9cd3677de408d9474768641cf8fc1a4f60c236e6aa3005aa50b9379bbb78a06b214b38345e2d6255452e46f529afdb71 +++ b/smg_comms/src/raw_types.ads 86acc0069ca2466f40782bd7c7643b97b465d520fcac61479a7e401fd1a2fc9a8d51360d94aad997a3e91265bd98555bfcc5a8453ad0ca352f0e2300729e0c52 @@ -13,6 +13,16 @@ Pragma Pure(Raw_Types); -- constants from SMG.COMMS standard specification + + -- RSA key size in octets + -- NB: this should MATCH the size of RSA key + -- as defined in the rsa implementation in C! + -- NOT imported here because: + -- a. it's C code that should import this, not the other way around. + -- b. it needs to be static here. + RSA_KEY_OCTETS : constant Positive := 490; + + -- size of a serpent-encrypted packet and message, in octets -- note that this corresponds to 1472/16 = 92 Serpent blocks -- NB: lengths are the same! @@ -33,6 +43,10 @@ subtype Octets_4 is Octets( 1 .. 4 ); subtype Octets_8 is Octets( 1 .. 8 ); + -- raw representations of RSA key components + subtype RSA_len is Octets ( 1 .. RSA_KEY_OCTETS); + subtype RSA_half is Octets( 1 .. RSA_KEY_OCTETS/2); + -- RSA packets and contained raw messages subtype RSA_Pkt is Octets( 1 .. RSA_PKT_OCTETS ); subtype RSA_Msg is Octets( 1 .. RSA_MSG_OCTETS ); diff -uNr a/smg_comms/src/rng.adb b/smg_comms/src/rng.adb --- a/smg_comms/src/rng.adb false +++ b/smg_comms/src/rng.adb 722719434c50879f456d3a82a31d172252e559fa7ee567dd81080fc32e7cdca2c3ab9717b58c54c4f80c67532c5055dffcab01a620c10fecf23227c3a5db36c4 @@ -0,0 +1,22 @@ + -- S.MG, 2018 + +with Ada.Exceptions; use Ada.Exceptions; + +package body RNG is + + procedure Get_Octets( O: out Raw_Types.Octets ) is + F : Octet_IO.File_Type; + begin + begin + Octet_IO.Open( File => F, Mode => Octet_IO.In_File, Name => RNG_PATH ); + for I in O'Range loop + Octet_IO.Read( F, O(I) ); + end loop; + Octet_IO.Close(F); + exception + when others => Raise_Exception(FG_Failure'Identity, + "Failed to access default RNG source!"); + end; + end Get_Octets; + +end RNG; diff -uNr a/smg_comms/src/rng.ads b/smg_comms/src/rng.ads --- a/smg_comms/src/rng.ads false +++ b/smg_comms/src/rng.ads ed853e32ebd9e0c93a01ef12eb5bf7e6765d841a4a8e67ff72b4ec69228985d8429f68b7727387f78d8e83bd8248c7724bfaa54495dd19da068979560a3610d4 @@ -0,0 +1,22 @@ + -- True Random octets generator reading from an FG and using Raw_Types. + -- S.MG, 2018 + +with Ada.Sequential_IO; +with Interfaces; +with Raw_Types; + +package RNG is + + -- for reading from the FG one Octet at a time + package Octet_IO is new Ada.Sequential_IO(Element_Type => + Interfaces.Unsigned_8); + + -- path to the FG; NB: the FG has to be initialized prior to using SMG Comms! + RNG_PATH: constant String := "/dev/ttyUSB0"; + + -- exception raised when FG is not accessible / read fails + FG_Failure : exception; + + -- reads O'Length octets from the FG at RNG_PATH + procedure Get_Octets( O: out Raw_Types.Octets ); +end RNG; diff -uNr a/smg_comms/src/rsa_oaep.adb b/smg_comms/src/rsa_oaep.adb --- a/smg_comms/src/rsa_oaep.adb false +++ b/smg_comms/src/rsa_oaep.adb e2c22c3d60357595fa21abfcf4535f455a3984272fd66ac9f36b14c263023c149afbb7862b4c8d9516cfe0aa9200141e141539db52906a09379bb92277b47529 @@ -0,0 +1,173 @@ + -- S.MG, 2018 + +with Interfaces; use Interfaces; +with OAEP; +with RNG; + +package body RSA_OAEP is + + -- OAEP + RSA with given public key. + -- Steps: + -- 1. repeat oaep.encrypt of Plain + -- until the result has first octet < than first octet of Key's modulus. + -- 2. RSA.encrypt with Key on the result from 1. + procedure Encrypt( Plain: in Raw_Types.Octets; + Key : in RSA_pkey; + Encr : out Raw_Types.RSA_len ) is + -- block obtained through OAEP padding of given input Plain + Blk : OAEP.OAEP_Block := ( others => 0 ); + Entropy : OAEP.OAEP_Block; + Len : constant Natural := entropy'Length; + begin + -- loop cond: 1st octet of oaep block is < 1st octet of key's modulus + loop + -- get random bits via RNG (FG) + RNG.Get_Octets( Entropy ); + + -- oaep encrypt + OAEP.OAEP_Encrypt( Plain, Entropy, Blk ); + + -- check that the oaep block is suitable i.e. comparison of 1st octet + if Blk(Blk'First) < Key.n(Key.n'First) then exit; end if; + + end loop; -- oaep block < modulus + + -- RSA encrypt + Public_RSA( Blk, Key, Encr ); + end; --Encrypt (OAEP+RSA) + + -- RSA+OAEP Decrypt + -- Steps: + -- 1. RSA Decrypt (secret key) + -- 2. OAEP Decrypt + procedure Decrypt( Encr : in Raw_Types.RSA_len; + Key : in RSA_skey; + Plain: out Raw_Types.Octets; + Plain_Len: out Natural; + Success: out Boolean) is + Blk : OAEP.OAEP_Block; + Msg : OAEP.OAEP_HALF; + Msg_Len : Natural; + begin + -- RSA decrypt with provided secret key + -- NB: result HAS TO BE AN OAEP BLOCK HERE! Even if - potentially - 0 led! + Private_RSA( Encr, Key, Blk ); + + -- OAEP decrypt + OAEP.OAEP_Decrypt(Blk, Msg_Len, Msg, Success); + -- switch to Length in OCTETS! + Msg_Len := Msg_Len / 8; + + -- check that result FITS in given output array - otherwise, fail + if Msg_Len > Plain'Length then + Success := FALSE; + Plain_Len := Msg_Len; --to give a clue to caller + else + Plain_Len := Msg_Len; + Plain( Plain'First .. + Plain'First + Plain_Len-1) := Msg( Msg'First .. + Msg'First + Plain_Len -1 ); + end if; + end Decrypt; + + -- helper methods + -- encrypt with public RSA key given as struct, Ada style + procedure Public_RSA( Plain: in Raw_Types.Octets; + Key : in RSA_pkey; + Encr : out Raw_Types.RSA_len) is + Encr_char : char_array( size_t(Encr'First) .. size_t(Encr'Last)); + Plain_char : char_array( size_t(Plain'First) .. size_t(Plain'Last)); + N_char : char_array( size_t(Key.n'First) .. size_t(Key.n'Last)); + E_char : char_array( size_t(Key.e'First) .. size_t(Key.e'Last)); + out_len : Integer; + begin + -- convert to char array + Octets_To_Char_Array( Plain, Plain_char ); + Octets_To_Char_Array( Key.n, N_char ); + Octets_To_Char_Array( Key.e, E_char ); + -- call C imported function + out_len := Public_RSA_C( Encr_char , Encr'Length, + Plain_char , Plain'Length, + N_char , Key.n'Length, + E_char , Key.e'Length); + -- convert back to octets + Char_Array_To_Octets( Encr_char, Encr ); + -- C code trims leading 0s -> need to move octets if out_len0); + end if; + -- no need to return anything! + end Public_RSA; + + procedure Private_RSA( Encr : in Raw_Types.RSA_len; + Key : in RSA_skey; + Plain : out Raw_Types.Octets) is + Plain_Char : char_array( size_t(Plain'First) .. size_t(Plain'Last) ); + Plain_Len : Integer; + Encr_Char : char_array( size_t(Encr'First) .. size_t(Encr'Last) ); + N_Char : char_array( size_t(Key.n'First) .. size_t(Key.n'Last) ); + E_Char : char_array( size_t(Key.e'First) .. size_t(Key.e'Last) ); + D_Char : char_array( size_t(Key.d'First) .. size_t(Key.d'Last) ); + P_Char : char_array( size_t(Key.p'First) .. size_t(Key.p'Last) ); + Q_Char : char_array( size_t(Key.q'First) .. size_t(Key.q'Last) ); + U_Char : char_array( size_t(Key.u'First) .. size_t(Key.u'Last) ); + begin + -- convert key and encrypted message to C char_arrays + Octets_To_Char_Array( Encr, Encr_Char ); + Octets_To_Char_Array( Key.n, N_Char ); + Octets_To_Char_Array( Key.e, E_Char ); + Octets_To_Char_Array( Key.d, D_Char ); + Octets_To_Char_Array( Key.p, P_Char ); + Octets_To_Char_Array( Key.q, Q_Char ); + Octets_To_Char_Array( Key.u, U_Char ); + -- call RSA decrypt via C_Wrappers + Plain_Len := Private_RSA_C( Plain_Char, Plain'Length, + Encr_Char , Encr'Length, + N_Char , Key.n'Length, + E_Char , Key.e'Length, + D_Char , Key.d'Length, + P_Char , Key.p'Length, + Q_Char , Key.q'Length, + U_Char , Key.u'Length); + -- convert result back to Octets + Char_Array_To_Octets( Plain_Char, Plain ); + -- if length < OAEP_Block'Length,it's 0-led and got trimmed, so move it + if Plain_Len < Plain'Length then + Plain(Plain'Last-Plain_Len+1..Plain'Last):= Plain(Plain'First .. + Plain'First + Plain_Len -1); + Plain(Plain'First .. Plain'Last-Plain_Len) := (others => 0); + end if; + -- no need to return anything! + end Private_RSA; + + procedure Octets_To_Char_Array( O : in Raw_Types.Octets; + A : out Interfaces.C.char_array) is + begin + -- check that lengths ARE THE SAME! + if A'Length /= O'Length then + raise Mismatched_Lengths_Error; + end if; + -- copy values over octet by octet + for I in 0 .. O'Length-1 loop + A( A'First + Interfaces.C.size_t( I )) := + Interfaces.C.Char( Character'Val(O(O'First + I))); + end loop; + end Octets_To_Char_Array; + + procedure Char_Array_To_Octets( A : in Interfaces.C.char_array; + O : out Raw_Types.Octets) is + begin + -- check that lengths ARE THE SAME! + if A'Length /= O'Length then + raise Mismatched_Lengths_Error; + end if; + -- copy values over octet by octet + for I in 0..O'Length -1 loop + O( O'First + I ) := Character'Pos( Character( + A( A'First + Interfaces.C.size_t( I )) )); + end loop; + end Char_Array_To_Octets; + +end RSA_OAEP; diff -uNr a/smg_comms/src/rsa_oaep.ads b/smg_comms/src/rsa_oaep.ads --- a/smg_comms/src/rsa_oaep.ads false +++ b/smg_comms/src/rsa_oaep.ads 30c0e084ac56702b73ebf5609107a8b21b71b269f34b37d9067a542a94dc0d26526480fe52efda976752b292be361ce4a4c7c1d3f2fad8cc100fc06ce6c78bf7 @@ -0,0 +1,129 @@ + -- Ada implementation of RSA with OAEP according to TMSR and Eulora spec + -- Uses: + -- - Eulora's raw types (Ada, raw_types.ads) + -- - Keccak hashes (Ada, keccak.ads/adb) + -- - OAEP schema (Ada, oaep.ads/adb) + -- - RNG (Ada, rng.ads/adb) for true random padding + -- - C wrappers lib (C, c_wrappers/) for: + -- - MPI (C, mpi/) + -- - RSA (C, rsa/rsa.c) + -- + -- S.MG, 2018 + +with Raw_Types; +with Interfaces.C; use Interfaces.C; + +package RSA_OAEP is + -- exception for mismatched lengths when converting octets <-> char arrays + Mismatched_Lengths_Error: exception; + + -- public RSA key with n,e stored as raw octets + type RSA_pkey is + record + n : Raw_Types.RSA_len; --public modulus + e : Raw_Types.RSA_half; --public exponent + end record; --RSA_pkey + + -- private (secret) RSA key with components stored as raw octets + type RSA_skey is + record + n : Raw_Types.RSA_len; --public modulus + e : Raw_Types.RSA_half; --public exponent + d : Raw_Types.RSA_len; --secret exponent e*d=1 mod phi; phi=(p-1)*(q-1) + p : Raw_Types.RSA_half; --prime p + q : Raw_Types.RSA_half; --prime q + u : Raw_Types.RSA_half; --inverse of p mod q; for faster calculations + end record; --RSA_skey + + -- Encryption RSA+OAEP (i.e. using public key) + -- NB: at most OAEP.MAX_LEN_MSG octets from Plain will be encrypted! + -- Relies directly on: + -- oaep.adb/ads + -- c_wrappers.c ( RSA ) + -- rng.adb/ads ( random padding ) + procedure Encrypt( Plain: in Raw_Types.Octets; + Key : in RSA_pkey; + Encr : out Raw_Types.RSA_len ); + + -- Decryption RSA+OAEP (i.e. using private/secret key) + -- The opposite of Encrypt above. + -- NB: Plain has to have ENOUGH space for result! + -- Result can be at most OAEP.MAX_LEN_MSG octets. + -- Relies directly on: + -- oaep.adb/ads + -- c_wrappers.c (RSA) + -- Plain_Len gives the length in OCTETS of the decrypted message. + procedure Decrypt( Encr : in Raw_Types.RSA_len; + Key : in RSA_skey; + Plain : out Raw_Types.Octets; + Plain_Len : out Natural; + Success : out Boolean); + + --helper methods: + -- mainly conversions to/from C's char* and imports from C_wrappers + -- encrypt with public RSA key given as struct, Ada style + -- NB: result is potentially 0-led (i.e. at end of Encr not at start!) + procedure Public_RSA( Plain: in Raw_Types.Octets; + Key : in RSA_pkey; + Encr : out Raw_Types.RSA_len); + + -- encrypt with public RSA key given as char arrays, via C_Wrappers + -- this returns the length of result because C functions trim leading 0s! + function Public_RSA_C( Encr : out Interfaces.C.char_array; + Encr_Len : in Integer; + Plain : in Interfaces.C.char_array; + Plain_Len : in Integer; + RSA_N : in Interfaces.C.char_array; + N_Len : in Integer; + RSA_E : in Interfaces.C.char_array; + E_Len : in Integer) + return Integer; + pragma Import(C, Public_RSA_C, "public_rsa_octets"); + + -- decrypt with private RSA key given as struct, Ada style + -- NB: Plain has to have ENOUGH space! + -- NB: Result is potentially 0-led (i.e. at the end of Plain, not at start!) + -- @return actual length of result + procedure Private_RSA( Encr : in Raw_Types.RSA_len; + Key : in RSA_skey; + Plain : out Raw_Types.Octets); + + -- encrypt with private/secret RSA key given as char arrays (via C_wrappers) + -- this returns length because C methods trim leading 0s + function Private_RSA_C( Plain : out Interfaces.C.char_array; + Plain_Len : in Integer; + Encr : in Interfaces.C.char_array; + Encr_Len : in Integer; + RSA_N : in Interfaces.C.char_array; + N_Len : in Integer; + RSA_E : in Interfaces.C.char_array; + E_Len : in Integer; + RSA_D : in Interfaces.C.char_array; + D_Len : in Integer; + RSA_P : in Interfaces.C.char_array; + P_Len : in Integer; + RSA_Q : in Interfaces.C.char_array; + Q_Len : in Integer; + RSA_U : in Interfaces.C.char_array; + U_Len : in Integer) + return Integer; + pragma Import( C, Private_RSA_C, "private_rsa_octets" ); + + -- convert from Ada's Octets (array of octets) to C's char* (char_array) + + -- This copies the octets from O to the beginning of A + -- NB: there are NO checks or memory allocations here! + -- Caller has to make sure that: + -- A has allocated space for at least O'Length octets! + procedure Octets_To_Char_Array( O : in Raw_Types.Octets; + A : out Interfaces.C.char_array); + + + -- This copies first O'Length characters from A to O + -- NB: this does NOT allocate /check memory! + -- Caller has to ensure that: + -- A has space at least O'Length characters + procedure Char_Array_To_Octets( A : in Interfaces.C.char_array; + O : out Raw_Types.Octets); + +end RSA_OAEP; diff -uNr a/smg_comms/tests/test_rsa_oaep.adb b/smg_comms/tests/test_rsa_oaep.adb --- a/smg_comms/tests/test_rsa_oaep.adb false +++ b/smg_comms/tests/test_rsa_oaep.adb faed716c9ff42cedc9353eed11cab82ee3be11da5c4ae417cda49ab092d68cd74a773052881ea831296aef905c7b22ee56a25886424219388e4457dcb99cf4fb @@ -0,0 +1,227 @@ + --S.MG, 2018 + +with Interfaces; use Interfaces; +with Interfaces.C; use Interfaces.C; +with RSA_OAEP; use RSA_OAEP; +with OAEP; use OAEP; +with Raw_Types; use Raw_Types; +with RNG; use RNG; +with Keccak; use Keccak; + +with Ada.Text_IO; use Ada.Text_IO; + +package body Test_RSA_OAEP is + + procedure test_char_array is + S : String := OAEP.TMSR_STR; + O : Octets := OAEP.TMSR; + A : char_array(0..O'Length-1) := (others => '0'); + B : Octets(0..O'Length -1) := (others => 0); + Fail : Boolean := FALSE; + begin + Octets_To_Char_Array(O, A); + Char_Array_To_Octets(A, B); + + if B /= O then + Put_Line("FAIL: char_array_to_octets"); + else + Put_Line("PASS: char_array_to_octets"); + end if; + + for I in 0..S'Length-1 loop + declare + C : Character := Character(A(A'First + size_t(I))); + E : Character := S(S'First + I); + begin + if C /= E then + Fail := TRUE; + Put("Error at pos " & Integer'Image(I) & ": "); + Put(Integer'Image(Character'Pos(C))); + Put_Line(" instead of " & Integer'Image(Character'Pos(E))); + end if; + end; + end loop; + if FAIL then + Put_Line("FAIL: test octets_to_char_array"); + else + Put_Line("PASS: test octets_to_char_array"); + end if; + end test_char_array; + + -- test OAEP encrypt + decrypt + procedure test_oaep is + Plain: Octets(1..MAX_LEN_MSG); + Short: Octets(0..10); + Encr : OAEP_Block; + Decr : OAEP_HALF; + Len : Natural; + Entropy: OAEP_Block; + Success : Boolean; + begin + RNG.Get_Octets(Plain); + RNG.Get_Octets(Entropy); + RNG.Get_Octets(Short); + + -- test full length message + OAEP_Encrypt(Plain, Entropy, Encr); + OAEP_Decrypt(Encr, Len, Decr, Success); + + if not Success or Len/8 /= Plain'Length then + Put_Line("FAIL: oaep encrypt/decrypt on max len message."); + else + if Decr(Decr'First..Decr'First+Len/8-1) /= + Plain(Plain'First..Plain'First+Len/8-1) then + Put_Line("FAIL: oaep encrypt/decrypt on max len message - " & + "result different from expected."); + else + Put_Line("PASS: oaep encrypt/decrypt on max len message."); + end if; + end if; + + -- test short message + OAEP_Encrypt(Short, Entropy, Encr); + OAEP_Decrypt(Encr, Len, Decr, Success); + if not Success or Len/8 /= Short'Length then + Put_Line("FAIL: oaep encrypt/decrypt on short message."); + else + if Decr(Decr'First..Decr'First+Len/8-1) /= + Short(Short'First..Short'First+Len/8-1) then + Put_Line("FAIL: oaep encrypt/decrypt on short message - " & + "result different from expected."); + else + Put_Line("PASS: oaep encrypt/decrypt on short message."); + end if; + end if; + + end test_oaep; + + -- test JUST RSA (i.e. without oaep) with RSA key pair previously generated + procedure test_rsa is + n: String := "C6579F8646180EED0DC1F02E0DDD2B43EABB3F702D79D9928E2CDA5E1D42DF5D9ED7773F80B1F8D9B0DB7D4D00F55647640D70768F63D3CED56A39C681D08D6191F318BB79DC969B470A7364D53335C8318EF35E39D5DF706AB6F2393C6DD2128C142DBAB1806EB35E26C908F0A48419313D2D0F33DD430655DBFEC722899EC21C238E8DB7003430BBC39BAD990F9887F6B03E1344F537EC97389B78DBC656718ACD7B0FDC13DD24534F417BC7A18F077A0C4227354CEA19670331B6CAA3DFC17BBA7E70C14510D9EB3B63F3014994EC87BD23E868C0AE6E9EC55027577F62C0280B2D7DD1135001844923E5455C4566E066B3FDE968C6BC4DC672F229FCE366440403D7A4F4A8BFBA5679B7D0844BA1231277D13A77C9E2B5A1CB138C1B7AB5B4D4832448723A3DE70ED2E86D5FC5174F949A02DE8E404304BEB95F9BF40F3AA3CA15622D2776294BE7E19233406FF563CB8C25A1CB5AADBC1899DA3F2AE38533931FE032EE3232C2CD4F219FADF95B91635C0762A476A4DE5013F4384093F0FB715028D97F93B2E6F057B99EE344D83ADF2686FD5C9C793928BEF3182E568C4339C36C744C8E9CA7D4B9A16AA039CBF6F38CC97B12D87644E94C9DBD6BC93A93A03ED61ECC5874586E3A310E958F858735E30019D345C62E5127B80652C8A970A14B31F03B3A157CD5"; + e: String := "F74D78E382FC19B064411C6C20E0FDB2985F843007A54C7D8400BB459468624126E7D175F397E55C57AF25858EAE2D2952FB7998C119A6103606733EB5E1D27FCA1FACF14ADE94101D383D1B25DA511805569BC344EAD384EDBF3F3A541B34887FE199D99D7F62E6E9D516F88D6F5AD3E020DF04D402A02CC628A0064362FE8516CF7CD6040E9521407AB90EE6B5AFFF9EA9EBB16A7D3407CE81FD3844F519880556AB94AB349C1F3BBB6FDB4C4B377FE4C091EBDC2C3A1BD3AA56382D8D80E7742B5C751008FD6ECDD2EC3B2E3B6C566F698ED672000B403766DD63C3ACBDE16A14FB02E83A2EB6AA018BFC0020401E790DEE24E9"; + d: String := "698DA05DA25B230211EEF0CBA12083A1457B749A11937AC9993859F69A3BF38D575E5166AF2EC88D77F1DF04E68AEA358EACF7659FD4722A4F5A1C8BA7676DA97A9FBA75451152F8F68887D3451A9CCFFFE9EB80979786E37495B17687A6212F77FA616E4C0CD8A8EB7AEB88EA6CCABB7F3E854FB94B35394A09F95F0D6F997947E865CC0606F437C30FE8C48D96FBF5E2F52807BC9E9ED7BBEB23D5C45EDDCD16FE2BF410A9A1E5EF879E71C0D41FAE270C0C5D442860103F8C3944E802F33DB38432F11F763A7AF593656108E4A98A44A8549913CE5DCEC1A6500F280E3190991B2B938561CFACD8BC5183AAC9A4914BFE52C3BE39BB83688E1DE52479107EF8E087DCDB409432FC954C6349407E81DDFB11AE92BABB32A31868597958C9C76E0B4156F380955F0E09C1F3B98BB4CDD59E1B5C7D8CC2AA7491B0D319D219CF459A527CE1AA2729DEC53269653BF0ED3E0253F4451168437E3B069E48350CA4C3EC82134E87135624C768D1330B0D70C6E447FD9945BF06FCB91AA334C0FD8EEF1ADBC15928B3DB62077B537F7E9F468CC95CD5AAFEAE1F760A863B48D07B163F670E2E5B550BB3E960230BA9FDAED9903AE2E669A7F3C4D1F1E25B8E8EDB8CC6E6FD2164E66F4E64ED77BEF1EC9E6CEA5624FD84C0680248746DC1C8187145F3CD2411659DAEAD11D"; + p: String := "CDD6F7673A501FB24C44D56CA1D434F6CB3334E193E02F8E906241906BCB7412DD2159825B24C22002F373E647C2DA62A854F3841C00FD5985D03227CA9B54A69380BA9D63BE738BDF9E65C247E43E1220EEDD9281DCA78B32A4E1B786B7697ED0C3195D5AF2990881B11D6FC9EC9F940067B2DEA2A516FAA5F269C98F0B67628A6D2708515A4A58041AA17A93E4C4DD95C85BC38351DDA1DCF3DFD91C505B22383132649CF9F9233852C7207075BCF43C71038F043F1EC53E9787FB051B7927D020903233C16897B993C8089D8464451F086E756CF20E46CE6ED4A6AC5C327A0AAFBECBAAFD177969E7C952C76A4F4E7C85BF7F63"; + q: String := "F6ACF0790A250802C8D45DAC549CDBEF7806D5877A5DF0069136A458FAC4F0B0858060A873DA6355A965A064A0BC1BBB874872CD7ED89674AD407533041E74BCA317EC73597D335115523F61A05071E5ED81EE2A05331F65D4DC7A25AD7938B124CF03F49154B6693FB0B598B33ABDEF85C599A57A9B7347EAFF82638E1CBC28FCDFFF1FF04A18C2DBF3938395C2F8D1782B43D3A25EF7633B5DDAC89EFD3BAA64D976425A0891E00B876E9DE9FE4B6492B0EA8DFC7C8DEEC61721356EC816295B1BD9CD9DA3E30D2D90DC9CB3987F4BE042104900E036F3044A016749EF910CCFB9F377A90849B4CCCF4471A74E67EF6C814C9467"; + u: String := "854B89ED10F52258D00D6B3FA7F1FD22752804668F51FF7806DB82E22CB8B3AA8448D9B8E9DB14D31A36AEC2BCFA89E341B7334D494E97ED8051244136192233332C4612D963E7B6AF2535FDB7FE97E28DDFEBDFB3E1AFC29D05DBDF37106A817D3AB1864C7F7F247982897EDA6A92BED47D9C68305CD170C7301ACEB05F8A6382E73CC7614B2D8D758669B3A99AB64114809254B0BE21F40341A5B48B9B032603B14875B87EB5E16603FD16552E146A0FC6964958DFC25AA9FFCCD1ED1F4DEAF9FBAA0D7357F5FF0803FEB9BA78E74AC6B3070F417CEC6CFC7A3CF1E305FC7B76B7ED71893999AF797B2EBDE41FE90F076CCEDBFB"; + Plain: OAEP_Block := (others => 0); + Decr : OAEP_Block := (others => 0); + Encr : RSA_len; + pkey: RSA_pkey; + skey: RSA_skey; + begin + -- initialize with RSA pair previously generated + Hex2Octets( n, skey.n ); + Hex2Octets( e, skey.e ); + Hex2Octets( d, skey.d ); + Hex2Octets( p, skey.p ); + Hex2Octets( q, skey.q ); + Hex2Octets( u, skey.u ); + -- copy n and e for public key + pkey.n := skey.n; + pkey.e := skey.e; + -- get random data + RNG.Get_Octets(Plain); + -- make first octet < RSA key's modulus first octet + Plain(Plain'First) := 16#00#; + -- naked rsa encrypt/decrypt +Put_Line("Encrypting with RSA public key..."); + Public_RSA( Plain, pkey, Encr ); +Put_Line("Decrypting with RSA private key..."); + Private_RSA( Encr, skey, Decr ); +Put_Line("Checking..."); + + -- check result + if Decr /= Plain then + Put_Line("FAIL: RSA encrypt/decrypt result doesn't match plain."); + else + Put_Line("PASS: RSA encrypt/decrypt"); + end if; + end test_rsa; + + -- test rsa+oaep with RSA key pair previously generated + procedure test_rsa_oaep is + n: String := "C6579F8646180EED0DC1F02E0DDD2B43EABB3F702D79D9928E2CDA5E1D42DF5D9ED7773F80B1F8D9B0DB7D4D00F55647640D70768F63D3CED56A39C681D08D6191F318BB79DC969B470A7364D53335C8318EF35E39D5DF706AB6F2393C6DD2128C142DBAB1806EB35E26C908F0A48419313D2D0F33DD430655DBFEC722899EC21C238E8DB7003430BBC39BAD990F9887F6B03E1344F537EC97389B78DBC656718ACD7B0FDC13DD24534F417BC7A18F077A0C4227354CEA19670331B6CAA3DFC17BBA7E70C14510D9EB3B63F3014994EC87BD23E868C0AE6E9EC55027577F62C0280B2D7DD1135001844923E5455C4566E066B3FDE968C6BC4DC672F229FCE366440403D7A4F4A8BFBA5679B7D0844BA1231277D13A77C9E2B5A1CB138C1B7AB5B4D4832448723A3DE70ED2E86D5FC5174F949A02DE8E404304BEB95F9BF40F3AA3CA15622D2776294BE7E19233406FF563CB8C25A1CB5AADBC1899DA3F2AE38533931FE032EE3232C2CD4F219FADF95B91635C0762A476A4DE5013F4384093F0FB715028D97F93B2E6F057B99EE344D83ADF2686FD5C9C793928BEF3182E568C4339C36C744C8E9CA7D4B9A16AA039CBF6F38CC97B12D87644E94C9DBD6BC93A93A03ED61ECC5874586E3A310E958F858735E30019D345C62E5127B80652C8A970A14B31F03B3A157CD5"; + e: String := "F74D78E382FC19B064411C6C20E0FDB2985F843007A54C7D8400BB459468624126E7D175F397E55C57AF25858EAE2D2952FB7998C119A6103606733EB5E1D27FCA1FACF14ADE94101D383D1B25DA511805569BC344EAD384EDBF3F3A541B34887FE199D99D7F62E6E9D516F88D6F5AD3E020DF04D402A02CC628A0064362FE8516CF7CD6040E9521407AB90EE6B5AFFF9EA9EBB16A7D3407CE81FD3844F519880556AB94AB349C1F3BBB6FDB4C4B377FE4C091EBDC2C3A1BD3AA56382D8D80E7742B5C751008FD6ECDD2EC3B2E3B6C566F698ED672000B403766DD63C3ACBDE16A14FB02E83A2EB6AA018BFC0020401E790DEE24E9"; + d: String := "698DA05DA25B230211EEF0CBA12083A1457B749A11937AC9993859F69A3BF38D575E5166AF2EC88D77F1DF04E68AEA358EACF7659FD4722A4F5A1C8BA7676DA97A9FBA75451152F8F68887D3451A9CCFFFE9EB80979786E37495B17687A6212F77FA616E4C0CD8A8EB7AEB88EA6CCABB7F3E854FB94B35394A09F95F0D6F997947E865CC0606F437C30FE8C48D96FBF5E2F52807BC9E9ED7BBEB23D5C45EDDCD16FE2BF410A9A1E5EF879E71C0D41FAE270C0C5D442860103F8C3944E802F33DB38432F11F763A7AF593656108E4A98A44A8549913CE5DCEC1A6500F280E3190991B2B938561CFACD8BC5183AAC9A4914BFE52C3BE39BB83688E1DE52479107EF8E087DCDB409432FC954C6349407E81DDFB11AE92BABB32A31868597958C9C76E0B4156F380955F0E09C1F3B98BB4CDD59E1B5C7D8CC2AA7491B0D319D219CF459A527CE1AA2729DEC53269653BF0ED3E0253F4451168437E3B069E48350CA4C3EC82134E87135624C768D1330B0D70C6E447FD9945BF06FCB91AA334C0FD8EEF1ADBC15928B3DB62077B537F7E9F468CC95CD5AAFEAE1F760A863B48D07B163F670E2E5B550BB3E960230BA9FDAED9903AE2E669A7F3C4D1F1E25B8E8EDB8CC6E6FD2164E66F4E64ED77BEF1EC9E6CEA5624FD84C0680248746DC1C8187145F3CD2411659DAEAD11D"; + p: String := "CDD6F7673A501FB24C44D56CA1D434F6CB3334E193E02F8E906241906BCB7412DD2159825B24C22002F373E647C2DA62A854F3841C00FD5985D03227CA9B54A69380BA9D63BE738BDF9E65C247E43E1220EEDD9281DCA78B32A4E1B786B7697ED0C3195D5AF2990881B11D6FC9EC9F940067B2DEA2A516FAA5F269C98F0B67628A6D2708515A4A58041AA17A93E4C4DD95C85BC38351DDA1DCF3DFD91C505B22383132649CF9F9233852C7207075BCF43C71038F043F1EC53E9787FB051B7927D020903233C16897B993C8089D8464451F086E756CF20E46CE6ED4A6AC5C327A0AAFBECBAAFD177969E7C952C76A4F4E7C85BF7F63"; + q: String := "F6ACF0790A250802C8D45DAC549CDBEF7806D5877A5DF0069136A458FAC4F0B0858060A873DA6355A965A064A0BC1BBB874872CD7ED89674AD407533041E74BCA317EC73597D335115523F61A05071E5ED81EE2A05331F65D4DC7A25AD7938B124CF03F49154B6693FB0B598B33ABDEF85C599A57A9B7347EAFF82638E1CBC28FCDFFF1FF04A18C2DBF3938395C2F8D1782B43D3A25EF7633B5DDAC89EFD3BAA64D976425A0891E00B876E9DE9FE4B6492B0EA8DFC7C8DEEC61721356EC816295B1BD9CD9DA3E30D2D90DC9CB3987F4BE042104900E036F3044A016749EF910CCFB9F377A90849B4CCCF4471A74E67EF6C814C9467"; + u: String := "854B89ED10F52258D00D6B3FA7F1FD22752804668F51FF7806DB82E22CB8B3AA8448D9B8E9DB14D31A36AEC2BCFA89E341B7334D494E97ED8051244136192233332C4612D963E7B6AF2535FDB7FE97E28DDFEBDFB3E1AFC29D05DBDF37106A817D3AB1864C7F7F247982897EDA6A92BED47D9C68305CD170C7301ACEB05F8A6382E73CC7614B2D8D758669B3A99AB64114809254B0BE21F40341A5B48B9B032603B14875B87EB5E16603FD16552E146A0FC6964958DFC25AA9FFCCD1ED1F4DEAF9FBAA0D7357F5FF0803FEB9BA78E74AC6B3070F417CEC6CFC7A3CF1E305FC7B76B7ED71893999AF797B2EBDE41FE90F076CCEDBFB"; + Plain: Octets(1..MAX_LEN_MSG) := (others=>20); + Short: Octets(1..10); + Decr : RSA_len; + Encr : RSA_len; + pkey: RSA_pkey; + skey: RSA_skey; + Success: Boolean; + Len : Natural; + begin + -- initialize with RSA pair previously generated + Hex2Octets( n, skey.n ); + Hex2Octets( e, skey.e ); + Hex2Octets( d, skey.d ); + Hex2Octets( p, skey.p ); + Hex2Octets( q, skey.q ); + Hex2Octets( u, skey.u ); + -- copy n and e for public key + pkey.n := skey.n; + pkey.e := skey.e; + + -- test with 0 message of length Plain'Length + RSA_OAEP.Encrypt(Plain, pkey, Encr); + RSA_OAEP.Decrypt(Encr, skey, Decr, Len, Success); + if (not Success) or Len /= Plain'Length + or Plain /= Decr(Decr'First..Decr'First+Plain'Length-1) then + Put_Line("FAIL: RSA_OAEP on max len message 20-filled."); + else + Put_Line("PASS: RSA_OAEP on max len message 20-filled."); + end if; + + -- get random data for "plain" message + RNG.Get_Octets(Plain); + RSA_OAEP.Encrypt(Plain, pkey, Encr); + RSA_OAEP.Decrypt(Encr, skey, Decr, Len, Success); + if (not Success) or Len /= Plain'Length + or Plain /= Decr(Decr'First..Decr'First+Plain'Length-1) then + Put_Line("FAIL: RSA_OAEP on random data of max length."); + else + Put_Line("PASS: RSA_OAEP on random data of max length."); + end if; + + -- get random data for "short" message + RNG.Get_Octets(Short); + RSA_OAEP.Encrypt(Short, pkey, Encr); + RSA_OAEP.Decrypt(Encr, skey, Decr, Len, Success); + if (not Success) or Len /= Short'Length + or Short /= Decr(Decr'First..Decr'First+Short'Length-1) then + Put_Line("FAIL: RSA_OAEP on random data of short length."); + else + Put_Line("PASS: RSA_OAEP on random data of short length."); + end if; + + end test_rsa_oaep; + +-- helper methods + procedure Hex2Octets( Hex: in String; O: out Raw_Types.Octets ) is + S : String := "16#AA#"; + -- to make sure that input String has EVEN number of chars (ie full octets) + H : String(1..Hex'Length+Hex'Length mod 2) := (others=>'0'); + begin + -- first char is 0 if needed to cover full octet... + H(H'Length-Hex'Length+1..H'Length) := Hex; + O := (others => 0); + for I in 0 .. H'Length/2-1 loop + S := "16#" & H(H'First + I*2 .. H'First + I*2 + 1) & "#"; + O(O'Last - H'Length/2 + 1 + I) := Unsigned_8'Value(S); + end loop; + end Hex2Octets; + + procedure PrintOctets( O: in Raw_Types.Octets; Title: in String ) is + begin + Put_Line(Title); + for V of O loop + Put(Unsigned_8'Image(V) & " "); + end loop; + New_Line; + end PrintOctets; + +end Test_RSA_OAEP; diff -uNr a/smg_comms/tests/test_rsa_oaep.ads b/smg_comms/tests/test_rsa_oaep.ads --- a/smg_comms/tests/test_rsa_oaep.ads false +++ b/smg_comms/tests/test_rsa_oaep.ads 7f930c7ea438151f273f7f788b381b7d29da7cbf2756c231953a56f1c47b14b28bf84b365cf803c56bc4759fc8e43c43a5ad152ed877bc30ccaed1e8d5bd11dc @@ -0,0 +1,13 @@ + -- S.MG, 2018 + +with Raw_Types; + +package Test_RSA_OAEP is + procedure test_char_array; + procedure test_oaep; -- test oaep only + procedure test_rsa; -- test rsa only + procedure test_rsa_oaep; -- test rsa+oaep + + procedure Hex2Octets( Hex: in String; O: out Raw_Types.Octets ); + procedure PrintOctets( O: in Raw_Types.Octets; Title: in String ); +end Test_RSA_OAEP; diff -uNr a/smg_comms/tests/testall.adb b/smg_comms/tests/testall.adb --- a/smg_comms/tests/testall.adb d2f582ffa3714e9756ad5a412ea1cacba2bbd0b4e9bba295217333ae4fc9b7b21afed99a5db413a3800e77dc407a500265de7140466342a9992403a351a1b68d +++ b/smg_comms/tests/testall.adb b150853b3e031aa9d0656a19645c7701c6f2fe543f2be6febde1d8b07d80eb4c4b690cb68d26a77d04d4ec0b85b7ab700bd20d4c2714f0f154fc3b848016b0ca @@ -2,9 +2,14 @@ with Test_Serpent; with Test_Packing; +with Test_RSA_OAEP; procedure testall is begin Test_Serpent.Selftest; Test_Packing.Test_Pack_Unpack; + Test_RSA_OAEP.test_char_array; + Test_RSA_OAEP.test_oaep; + Test_RSA_OAEP.test_rsa; + Test_RSA_OAEP.test_rsa_oaep; end testall;