private static void PrepareForUpload(ISimpleJsonRest web, APIBodySync body, StandardFileTag tag, List <StandardFileNote> allNotes, APIResultAuthorize token, StandardNoteConfig cfg, bool delete) { var jsnContent = new ContentTag { title = tag.Title, references = allNotes .Where(n => n.InternalTags.Any(it => it.UUID == tag.UUID)) .Select(n => new APIResultContentRef { content_type = "Note", uuid = n.ID }) .ToList(), }; Debug.Assert(tag.UUID != null, "tag.UUID != null"); var cdNote = StandardNoteCrypt.EncryptContent(token.version, web.SerializeJson(jsnContent), tag.UUID.Value, token.masterkey, token.masterauthkey); body.items.Add(new APIBodyItem { content_type = "Tag", uuid = tag.UUID.Value, enc_item_key = cdNote.enc_item_key, auth_hash = cdNote.auth_hash, content = cdNote.enc_content, deleted = delete, }); }
private static APIResultAuthorize Authenticate003(ISimpleJsonRest web, APIAuthParams apiparams, string mail, string uip, AlephLogger logger) { try { logger.Debug(StandardNotePlugin.Name, $"AutParams[version:{apiparams.version}, pw_cost:{apiparams.pw_cost}, pw_nonce:{apiparams.pw_nonce}]"); if (apiparams.pw_cost < 100000) { throw new StandardNoteAPIException($"Account pw_cost is too small ({apiparams.pw_cost})"); } var salt = StandardNoteCrypt.SHA256(string.Join(":", mail, "SF", "003", apiparams.pw_cost.ToString(), apiparams.pw_nonce)); byte[] bytes = PBKDF2.GenerateDerivedKey(768 / 8, Encoding.UTF8.GetBytes(uip), Encoding.UTF8.GetBytes(salt), apiparams.pw_cost, PBKDF2.HMACType.SHA512); var pw = bytes.Skip(0 * (bytes.Length / 3)).Take(bytes.Length / 3).ToArray(); var mk = bytes.Skip(1 * (bytes.Length / 3)).Take(bytes.Length / 3).ToArray(); var ak = bytes.Skip(2 * (bytes.Length / 3)).Take(bytes.Length / 3).ToArray(); var reqpw = EncodingConverter.ByteToHexBitFiddleUppercase(pw).ToLower(); APIResultAuthorize tok; try { tok = web.PostTwoWay <APIResultAuthorize>(new APIRequestUser { email = mail, password = reqpw }, "auth/sign_in"); } catch (RestStatuscodeException e1) { if (e1.StatusCode / 100 == 4 && !string.IsNullOrWhiteSpace(e1.HTTPContent)) { var req = web.ParseJsonOrNull <APIBadRequest>(e1.HTTPContent); if (req != null) { throw new StandardNoteAPIException($"Server returned status {e1.StatusCode}.\nMessage: '{req.error.message}'", e1); } } throw; } tok.masterkey = mk; tok.masterauthkey = ak; tok.version = "003"; return(tok); } catch (RestException) { throw; } catch (StandardNoteAPIException) { throw; } catch (Exception e) { throw new StandardNoteAPIException("Authentification with StandardNoteAPI failed.", e); } }
public static (byte[] mk, byte[] sp, string reqpw) CreateAuthData004(StandardNoteAPI.APIResultAuthParams apiparams, string mail, string uip) { var salt = StandardNoteCrypt.SHA256Bytes(string.Join(":", apiparams.identifier, apiparams.pw_nonce)).Take(128 / 8).ToArray(); var derivedKey = ANCrypt.Argon2(Encoding.UTF8.GetBytes(uip), salt, 5, 64 * 1024, 64); var masterKey = derivedKey.Skip(00).Take(32).ToArray(); var serverPassword = derivedKey.Skip(32).Take(32).ToArray(); var requestPassword = EncodingConverter.ByteToHexBitFiddleLowercase(serverPassword); return(masterKey, serverPassword, requestPassword); }
private static void PrepareForUpload(ISimpleJsonRest web, APIBodySync body, StandardFileNote note, List <StandardFileTag> tags, APIResultAuthorize token, StandardNoteConfig cfg, bool delete) { var appdata = new Dictionary <string, Dictionary <string, object> >(); SetAppDataBool(appdata, APPDATA_PINNED, note.IsPinned); SetAppDataBool(appdata, APPDATA_LOCKED, note.IsLocked); var jsnContent = new ContentNote { title = note.InternalTitle, text = note.Text, references = new List <APIResultContentRef>(), appData = appdata, }; foreach (var itertag in note.InternalTags.ToList()) { var itag = itertag; if (itag.UUID == null) { var newTag = tags.FirstOrDefault(e => e.Title == itag.Title); if (newTag == null) { newTag = new StandardFileTag(Guid.NewGuid(), itag.Title); tags.Add(newTag); } note.UpgradeTag(itag, newTag); itag = newTag; } Debug.Assert(itag.UUID != null, "itag.UUID != null"); jsnContent.references.Add(new APIResultContentRef { content_type = "Tag", uuid = itag.UUID.Value }); } var cdNote = StandardNoteCrypt.EncryptContent(token.version, web.SerializeJson(jsnContent), note.ID, token.masterkey, token.masterauthkey); body.items.Add(new APIBodyItem { content_type = "Note", uuid = note.ID, created_at = note.CreationDate, enc_item_key = cdNote.enc_item_key, auth_hash = cdNote.auth_hash, content = cdNote.enc_content, deleted = delete, }); }
private static SyncResultTag CreateTag(ISimpleJsonRest web, APIResultItem encTag, APIResultAuthorize authToken) { if (encTag.deleted) { return(new SyncResultTag { deleted = encTag.deleted, title = "", uuid = encTag.uuid, enc_item_key = encTag.enc_item_key, item_key = "", references = new List <APIResultContentRef>(), }); } ContentTag content; try { var contentJson = StandardNoteCrypt.DecryptContent(encTag.content, encTag.enc_item_key, encTag.auth_hash, authToken.masterkey, authToken.masterauthkey); Logger.Debug( StandardNotePlugin.Name, $"DecryptContent of tag {encTag.uuid:B}", $"[content]:\r\n{encTag.content}\r\n" + $"[enc_item_key]:\r\n{encTag.enc_item_key}\r\n" + $"[auth_hash]:\r\n{encTag.auth_hash}\r\n" + $"\r\n\r\n" + $"[contentJson]:\r\n{contentJson}\r\n"); content = web.ParseJsonWithoutConverter <ContentTag>(contentJson); } catch (RestException) { throw; } catch (Exception e) { throw new StandardNoteAPIException("Cannot decrypt note with local masterkey", e); } return(new SyncResultTag { deleted = encTag.deleted, title = content.title, uuid = encTag.uuid, enc_item_key = encTag.enc_item_key, references = content.references, }); }
public static (byte[] pw, byte[] mk, byte[] ak, string reqpw) CreateAuthData003(StandardNoteAPI.APIResultAuthParams apiparams, string mail, string uip) { if (apiparams.pw_cost < 100000) { throw new StandardNoteAPIException($"Account pw_cost is too small ({apiparams.pw_cost})"); } var salt = StandardNoteCrypt.SHA256Hex(string.Join(":", mail, "SF", "003", apiparams.pw_cost.ToString(), apiparams.pw_nonce)); byte[] bytes = PBKDF2.GenerateDerivedKey(768 / 8, Encoding.UTF8.GetBytes(uip), Encoding.UTF8.GetBytes(salt), apiparams.pw_cost, PBKDF2.HMACType.SHA512); var pw = bytes.Skip(0 * (bytes.Length / 3)).Take(bytes.Length / 3).ToArray(); var mk = bytes.Skip(1 * (bytes.Length / 3)).Take(bytes.Length / 3).ToArray(); var ak = bytes.Skip(2 * (bytes.Length / 3)).Take(bytes.Length / 3).ToArray(); var reqpw = EncodingConverter.ByteToHexBitFiddleUppercase(pw).ToLower(); return(pw, mk, ak, reqpw); }
private static void PrepareTagForUpload(ISimpleJsonRest web, APIBodySync body, ref List <APIRawBodyItem> bodyraw, StandardFileTag tag, APIResultAuthorize token, bool delete) { var objContent = new ContentTag { title = tag.Title, references = tag .References .Select(n => new APIResultContentRef { content_type = "Note", uuid = n }) .ToList(), }; Debug.Assert(tag.UUID != null, "tag.UUID != null"); var jsonContent = web.SerializeJson(objContent); var cryptData = StandardNoteCrypt.EncryptContent(token.version, jsonContent, tag.UUID.Value, token.masterkey, token.masterauthkey); body.items.Add(new APIBodyItem { content_type = "Tag", uuid = tag.UUID.Value, enc_item_key = cryptData.enc_item_key, auth_hash = cryptData.auth_hash, content = cryptData.enc_content, deleted = delete, }); bodyraw.Add(new APIRawBodyItem { content_type = "Tag", uuid = tag.UUID.Value, content = jsonContent, deleted = delete, }); }
private static StandardFileNote CreateNote(ISimpleJsonRest web, StandardNoteConnection conn, APIResultItem encNote, APIResultAuthorize authToken, StandardNoteConfig cfg, StandardNoteData dat) { if (encNote.deleted) { var nd = new StandardFileNote(encNote.uuid, cfg, conn.HConfig) { CreationDate = encNote.created_at, Text = "", InternalTitle = "", AuthHash = encNote.auth_hash, ContentVersion = StandardNoteCrypt.GetSchemaVersion(encNote.content), }; nd.ModificationDate = encNote.updated_at; return(nd); } ContentNote content; try { var contentJson = StandardNoteCrypt.DecryptContent(encNote.content, encNote.enc_item_key, encNote.auth_hash, authToken.masterkey, authToken.masterauthkey); Logger.Debug( StandardNotePlugin.Name, $"DecryptContent of note {encNote.uuid:B}", $"[content]:\r\n{encNote.content}\r\n" + $"[enc_item_key]:\r\n{encNote.enc_item_key}\r\n" + $"[auth_hash]:\r\n{encNote.auth_hash}\r\n" + $"\r\n\r\n" + $"[contentJson]:\r\n{contentJson}\r\n"); content = web.ParseJsonWithoutConverter <ContentNote>(contentJson); } catch (RestException) { throw; } catch (Exception e) { throw new StandardNoteAPIException("Cannot decrypt note with local masterkey", e); } var n = new StandardFileNote(encNote.uuid, cfg, conn.HConfig) { Text = StandardNoteConfig.REX_LINEBREAK.Replace(content.text, Environment.NewLine), InternalTitle = content.title, AuthHash = encNote.auth_hash, ContentVersion = StandardNoteCrypt.GetSchemaVersion(encNote.content), IsPinned = GetAppDataBool(content.appData, APPDATA_PINNED, false), IsLocked = GetAppDataBool(content.appData, APPDATA_LOCKED, false), }; var refTags = new List <StandardFileTagRef>(); foreach (var cref in content.references) { if (cref.content_type == "Note") { // ignore } else if (dat.Tags.Any(t => t.UUID == cref.uuid)) { refTags.Add(new StandardFileTagRef(cref.uuid, dat.Tags.First(t => t.UUID == cref.uuid).Title)); } else if (cref.content_type == "Tag") { Logger.Warn(StandardNotePlugin.Name, $"Reference to missing tag {cref.uuid} in note {encNote.uuid}"); } else { Logger.Error(StandardNotePlugin.Name, $"Downloaded note contains an unknown reference :{cref.uuid} ({cref.content_type}) in note {encNote.uuid}"); } } foreach (var tref in dat.Tags.Where(tag => tag.References.Any(tref => tref == encNote.uuid))) { refTags.Add(new StandardFileTagRef(tref.UUID, tref.Title)); } refTags = refTags.DistinctBy(t => t.UUID).ToList(); n.SetTags(refTags); n.SetReferences(content.references); n.CreationDate = encNote.created_at; n.ModificationDate = encNote.updated_at; return(n); }
private static void PrepareNoteForUpload(ISimpleJsonRest web, APIBodySync body, ref List <APIRawBodyItem> bodyraw, StandardFileNote note, List <StandardFileTag> allTags, APIResultAuthorize token, StandardNoteConfig cfg, bool delete) { var appdata = new Dictionary <string, Dictionary <string, object> >(); SetAppDataBool(appdata, APPDATA_PINNED, note.IsPinned); SetAppDataBool(appdata, APPDATA_LOCKED, note.IsLocked); var objContent = new ContentNote { title = note.InternalTitle, text = note.Text.Replace("\r\n", "\n"), references = new List <APIResultContentRef>(), appData = appdata, }; // Set correct tag UUID if tag already exists foreach (var itertag in note.InternalTags.ToList()) { var itag = itertag; if (itag.UUID == null) { var newTag = allTags.FirstOrDefault(e => e.Title == itag.Title)?.ToRef(); if (newTag == null) { newTag = new StandardFileTagRef(Guid.NewGuid(), itag.Title); allTags.Add(new StandardFileTag(newTag.UUID, newTag.Title, Enumerable.Repeat(note.ID, 1))); } note.UpgradeTag(itag, newTag); } } // Notes no longer have references to their tags (see issue #88) //foreach (var itertag in note.InternalTags.ToList()) //{ // Debug.Assert(itertag.UUID != null, "itertag.UUID != null"); // jsnContent.references.Add(new APIResultContentRef { content_type = "Tag", uuid = itertag.UUID.Value }); //} var jsonContent = web.SerializeJson(objContent); var cryptData = StandardNoteCrypt.EncryptContent(token.version, jsonContent, note.ID, token.masterkey, token.masterauthkey); body.items.Add(new APIBodyItem { content_type = "Note", uuid = note.ID, created_at = note.CreationDate, enc_item_key = cryptData.enc_item_key, auth_hash = cryptData.auth_hash, content = cryptData.enc_content, deleted = delete, }); bodyraw.Add(new APIRawBodyItem { content_type = "Note", uuid = note.ID, created_at = note.CreationDate, content = jsonContent, deleted = delete, }); }
private static StandardFileNote CreateNote(ISimpleJsonRest web, StandardNoteConnection conn, APIResultItem encNote, APIResultAuthorize authToken, StandardNoteConfig cfg, StandardNoteData dat) { if (encNote.deleted) { var nd = new StandardFileNote(encNote.uuid, cfg, conn.HConfig) { CreationDate = encNote.created_at, AuthHash = encNote.auth_hash, ContentVersion = StandardNoteCrypt.GetSchemaVersion(encNote.content), }; nd.RawModificationDate = encNote.updated_at; return(nd); } ContentNote content; string appDataContentString; try { var contentJson = StandardNoteCrypt.DecryptContent(encNote.content, encNote.enc_item_key, encNote.auth_hash, authToken.masterkey, authToken.masterauthkey); Logger.Debug( StandardNotePlugin.Name, $"DecryptContent of note {encNote.uuid:B}", $"[content]:\r\n{encNote.content}\r\n" + $"[enc_item_key]:\r\n{encNote.enc_item_key}\r\n" + $"[auth_hash]:\r\n{encNote.auth_hash}\r\n" + $"\r\n\r\n" + $"[contentJson]:\r\n{contentJson}\r\n"); content = web.ParseJsonWithoutConverter <ContentNote>(contentJson); appDataContentString = web.ParseJsonAndGetSubJson(contentJson, "appData", string.Empty); } catch (RestException) { throw; } catch (Exception e) { throw new StandardNoteAPIException("Cannot decrypt note with local masterkey", e); } var n = new StandardFileNote(encNote.uuid, cfg, conn.HConfig); using (n.SuppressDirtyChanges()) { n.Text = StandardNoteConfig.REX_LINEBREAK.Replace(content.text, Environment.NewLine); n.InternalTitle = content.title; n.AuthHash = encNote.auth_hash; n.ContentVersion = StandardNoteCrypt.GetSchemaVersion(encNote.content); n.IsPinned = GetAppDataBool(content.appData, APPDATA_PINNED, false); n.IsLocked = GetAppDataBool(content.appData, APPDATA_LOCKED, false); n.IsArchived = GetAppDataBool(content.appData, APPDATA_ARCHIVED, false); n.IsProtected = content.@protected; n.IsHidePreview = content.hidePreview; var refTags = new List <StandardFileTagRef>(); foreach (var cref in content.references) { if (cref.content_type == "Note") { // ignore } else if (dat.Tags.Any(t => t.UUID == cref.uuid)) { refTags.Add(new StandardFileTagRef(cref.uuid, dat.Tags.First(t => t.UUID == cref.uuid).Title)); } else if (cref.content_type == "Tag") { Logger.Warn(StandardNotePlugin.Name, $"Reference to missing tag {cref.uuid} in note {encNote.uuid}"); } else { Logger.Error(StandardNotePlugin.Name, $"Downloaded note contains an unknown reference :{cref.uuid} ({cref.content_type}) in note {encNote.uuid}"); } } foreach (var tref in dat.Tags.Where(tag => tag.References.Any(tref => tref == encNote.uuid))) { refTags.Add(new StandardFileTagRef(tref.UUID, tref.Title)); } refTags = refTags.DistinctBy(t => t.UUID).ToList(); n.SetTags(refTags); n.SetReferences(content.references); n.CreationDate = encNote.created_at; n.RawModificationDate = encNote.updated_at; n.ClientUpdatedAt = GetAppDataDTO(content.appData, APPDATA_CLIENTUPDATEDAT, null); n.NoteCreationDate = GetAppDataDTO(content.appData, APPDATA_NOTECDATE, null); n.NoteModificationDate = GetAppDataDTO(content.appData, APPDATA_NOTEMDATE, null); n.TextModificationDate = GetAppDataDTO(content.appData, APPDATA_TEXTMDATE, null); n.TitleModificationDate = GetAppDataDTO(content.appData, APPDATA_TITLEMDATE, null); n.TagsModificationDate = GetAppDataDTO(content.appData, APPDATA_TAGSMDATE, null); n.PathModificationDate = GetAppDataDTO(content.appData, APPDATA_PATHMDATE, null); n.RawAppData = appDataContentString; } return(n); }