DecentralisedNameInfo.vala 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. using Invercargill;
  2. namespace Riddle {
  3. public class DecentralisedNameInfo : NameInfo {
  4. public uint8[] public_key { get; protected set; }
  5. private uint8[] raw_data { get; protected set; }
  6. public override string get_encoded() {
  7. return Base64.encode(raw_data);
  8. }
  9. public DecentralisedNameInfo.from_string(string encoded_name_info) throws NameInfoError {
  10. raw_data = Base64.decode (encoded_name_info);
  11. public_key = raw_data[0:Sodium.Asymmetric.Signing.PUBLIC_KEY_BYTES];
  12. var signed_message = raw_data[Sodium.Asymmetric.Signing.PUBLIC_KEY_BYTES:];
  13. var data = Sodium.Asymmetric.Signing.verify (signed_message, public_key);
  14. if(data == null) {
  15. throw new NameInfoError.BAD_DATA("Invalid signature");
  16. }
  17. parse_base_info ((string)data);
  18. validate_base_info();
  19. if(!name.has_suffix (".rns")) {
  20. throw new NameInfoError.INVALID("Decentralised names must end in '.rns'.");
  21. }
  22. var expected_suffix = generate_suffix(get_root_name(name), public_key);
  23. if(!name.has_suffix (expected_suffix)) {
  24. throw new NameInfoError.INVALID("The name and private key combination is not valid.");
  25. }
  26. }
  27. public DecentralisedNameInfo(string name, string key, DateTime expiry, Enumerable<NameProperty> properties) {
  28. var keys = key.split(":");
  29. public_key = Base64.decode(keys[0]);
  30. var secret_key = Base64.decode(keys[1]);
  31. var name_parts = name.split(".");
  32. var root_name = name_parts[name_parts.length-1];
  33. this.name = name + generate_suffix(root_name, public_key);
  34. expires = expiry.to_utc();
  35. effective = new DateTime.now_utc();
  36. this.properties = properties.to_sequence();
  37. var data = stringify_base_info();
  38. var signed = Sodium.Asymmetric.Signing.sign (data.data, secret_key);
  39. // Data is public-key followed by signed data
  40. raw_data = new uint8[public_key.length + signed.length];
  41. for(var i = 0; i < raw_data.length; i++) {
  42. if(i < public_key.length) {
  43. raw_data[i] = public_key[i];
  44. }
  45. else {
  46. raw_data[i] = signed[i-public_key.length];
  47. }
  48. }
  49. }
  50. public static string generate_key() {
  51. var pk = new uint8[Sodium.Asymmetric.Signing.PUBLIC_KEY_BYTES];
  52. var sk = new uint8[Sodium.Asymmetric.Signing.SECRET_KEY_BYTES];
  53. Sodium.Asymmetric.Signing.generate_keypair (pk, sk);
  54. var pk_enc = Base64.encode (pk);
  55. var sk_enc = Base64.encode (sk);
  56. return @"$pk_enc:$sk_enc";
  57. }
  58. public static string generate_suffix(string root_name, uint8[] public_key) {
  59. var checksum = new Checksum(ChecksumType.SHA512);
  60. var name_data = root_name.data;
  61. checksum.update(name_data, name_data.length);
  62. checksum.update(public_key, public_key.length);
  63. var digest = new uint8[64];
  64. size_t size = digest.length;
  65. checksum.get_digest(digest, ref size);
  66. var suffix = @".$(encode_hash(digest)).rns";
  67. return suffix;
  68. }
  69. public static string get_root_name(string name) {
  70. var parts = name.split(".");
  71. return parts[parts.length - 3];
  72. }
  73. private const string ENCODING_CHARS = "abcdefghijklmnopqrstuvwxyz234567";
  74. private static string encode_hash(uint8[] data) {
  75. var s = new char[6];
  76. for(var i = 0; i < 6; i++) {
  77. var v = data[i*10];
  78. var ev = v / 8;
  79. s[i] = ENCODING_CHARS[ev];
  80. }
  81. return (string)s;
  82. }
  83. }
  84. }