Bladeren bron

LibCrypto: Add ::import_data() and ::export_data() to UnsignedBigInteger

These functions allow conversion to-and-from big-endian buffers
This commit also adds a ""_bigint operator for easy bigint use
AnotherTest 5 jaren geleden
bovenliggende
commit
6b742c69bd

+ 28 - 0
Libraries/LibCrypto/BigInt/UnsignedBigInteger.cpp

@@ -312,4 +312,32 @@ UnsignedBigInteger UnsignedBigInteger::create_invalid()
     invalid.invalidate();
     return invalid;
 }
+
+// FIXME: in great need of optimisation
+UnsignedBigInteger UnsignedBigInteger::import_data(const u8* ptr, size_t length)
+{
+    UnsignedBigInteger integer { 0 };
+
+    for (size_t i = 0; i < length; ++i) {
+        auto part = UnsignedBigInteger { ptr[length - i - 1] }.shift_left(8 * i);
+        integer = integer.add(part);
+    }
+
+    return integer;
+}
+
+size_t UnsignedBigInteger::export_data(AK::ByteBuffer& data)
+{
+    UnsignedBigInteger copy { *this };
+
+    size_t size = trimmed_length() * sizeof(u32);
+    size_t i = 0;
+    for (; i < size; ++i) {
+        if (copy.length() == 0)
+            break;
+        data[size - i - 1] = copy.m_words[0] & 0xff;
+        copy = copy.divide(256).quotient;
+    }
+    return i;
+}
 }

+ 17 - 0
Libraries/LibCrypto/BigInt/UnsignedBigInteger.h

@@ -25,6 +25,7 @@
  */
 
 #pragma once
+#include <AK/ByteBuffer.h>
 #include <AK/LogStream.h>
 #include <AK/String.h>
 #include <AK/Types.h>
@@ -48,6 +49,16 @@ public:
     static UnsignedBigInteger from_base10(const String& str);
     static UnsignedBigInteger create_invalid();
 
+    static UnsignedBigInteger import_data(const AK::StringView& data) { return import_data((const u8*)data.characters_without_null_termination(), data.length()); }
+    static UnsignedBigInteger import_data(const u8* ptr, size_t length);
+
+    size_t export_data(AK::ByteBuffer& data);
+    size_t export_data(const u8* ptr, size_t length)
+    {
+        auto buffer = ByteBuffer::wrap(ptr, length);
+        return export_data(buffer);
+    }
+
     const AK::Vector<u32>& words() const { return m_words; }
 
     UnsignedBigInteger add(const UnsignedBigInteger& other) const;
@@ -103,3 +114,9 @@ operator<<(const LogStream& stream, const Crypto::UnsignedBigInteger value)
     }
     return stream;
 }
+
+inline Crypto::UnsignedBigInteger
+operator""_bigint(const char* string, size_t length)
+{
+    return Crypto::UnsignedBigInteger::from_base10({ string, length });
+}

+ 21 - 0
Userland/test-crypto.cpp

@@ -183,6 +183,9 @@ auto main(int argc, char** argv) -> int
         puts("\tencrypt -- Access encryption functions");
         puts("\tdecrypt -- Access decryption functions");
         puts("\tlist -- List all known modes");
+        puts("these modes only contain tests");
+        puts("\tbigint -- Run big integer test suite");
+        puts("\tpk -- Run Public-key system tests");
         return 0;
     }
 
@@ -308,6 +311,7 @@ void bigint_subtraction();
 void bigint_multiplication();
 void bigint_division();
 void bigint_base10();
+void bigint_import_export();
 
 int aes_cbc_tests()
 {
@@ -805,6 +809,7 @@ int bigint_tests()
     bigint_multiplication();
     bigint_division();
     bigint_base10();
+    bigint_import_export();
     return 0;
 }
 
@@ -1027,3 +1032,19 @@ void bigint_base10()
         }
     }
 }
+
+void bigint_import_export()
+{
+    {
+        I_TEST((BigInteger | BigEndian Decode / Encode roundtrip));
+        u8 random_bytes[128];
+        u8 target_buffer[128];
+        arc4random_buf(random_bytes, 128);
+        auto encoded = Crypto::UnsignedBigInteger::import_data(random_bytes, 128);
+        encoded.export_data(target_buffer, 128);
+        if (memcmp(target_buffer, random_bytes, 128) != 0)
+            FAIL(Could not roundtrip);
+        else
+            PASS;
+    }
+}