// ĠCopyright Ġ 2 0 0 0 - 2 0 1 8 ĠJetBrains Ġs . r . o . ĠUse Ġof Ġthis Ġsource Ġcode Ġis Ġgoverned Ġby Ġthe ĠApache Ġ 2 . 0 Ġlicense Ġthat Ġcan Ġbe Ġfound Ġin Ġthe ĠLICENSE Ġfile . Ċ package Ġcom . intellij . credential Store . k db x Ċ Ċ import Ġcom . intellij . credential Store . One Time String Ċ import Ġcom . intellij . credential Store . create Secure Random Ċ import Ġcom . intellij . credential Store . generate Bytes Ċ import Ġcom . intellij . util . get OrCreate Ċ import Ġcom . intellij . util . io . toByteArray Ċ import Ġcom . intellij . util . load Element Ċ import Ġorg . bouncycastle . crypto . Skipping Stream Cipher Ċ import Ġorg . bouncycastle . crypto . engines . Ch a Ch a 7 5 3 9 Engine Ċ import Ġorg . bouncycastle . crypto . params . Key Parameter Ċ import Ġorg . bouncycastle . crypto . params . Parameters With IV Ċ import Ġorg . j dom . Element Ċ import Ġjava . io . OutputStream Ċ import Ġjava . nio . ByteBuffer Ċ import Ġjava . nio . Char Buffer Ċ import Ġjava . security . Secure Random Ċ import Ġjava . time . LocalDateTime Ċ import Ġjava . time . Zone Offset Ċ import Ġjava . time . format . DateTime Formatter Ċ import Ġjava . util .* Ċ Ċ internal Ġobject ĠK db x Db Element Names Ġ{ ĊĠ Ġconst Ġval Ġgroup Ġ= Ġ" Group " ĊĠ Ġconst Ġval Ġentry Ġ= Ġ" Entry " ĊĊĠ Ġconst Ġval Ġroot Ġ= Ġ" Root " ĊĊĠ Ġconst Ġval Ġname Ġ= Ġ" Name " Ċ } Ċ Ċ internal Ġval ĠLOC ATION _ CHANGED Ġ= ĠarrayOf (" Times ", Ġ" Location Changed ") Ċ internal Ġval ĠUS AGE _ COUNT _ ELEMENT _ NAME Ġ= ĠarrayOf (" Times ", Ġ" Usage Count ") Ċ internal Ġval ĠEX PI RES _ ELEMENT _ NAME Ġ= ĠarrayOf (" Times ", Ġ" Expires ") Ċ internal Ġval ĠICON _ ELEMENT _ NAME Ġ= ĠarrayOf (" Icon ID ") Ċ internal Ġval ĠUUID _ ELEMENT _ NAME Ġ= ĠarrayOf (" UUID ") Ċ internal Ġval ĠLAST _ MO DIF ICATION _ TIME _ ELEMENT _ NAME Ġ= ĠarrayOf (" Times ", Ġ" Last Modification Time ") Ċ internal Ġval ĠCRE ATION _ TIME _ ELEMENT _ NAME Ġ= ĠarrayOf (" Times ", Ġ" Creation Time ") Ċ internal Ġval ĠLAST _ ACCESS _ TIME _ ELEMENT _ NAME Ġ= ĠarrayOf (" Times ", Ġ" Last Access Time ") Ċ internal Ġval ĠEX PI RY _ TIME _ ELEMENT _ NAME Ġ= ĠarrayOf (" Times ", Ġ" Expiry Time ") Ċ Ċ internal Ġvar Ġdate Formatter Ġ= ĠDateTime Formatter . of Pattern (" yyyy - MM - dd ' T ' HH : mm : ss ' Z '") Ċ Ċ private Ġfun Ġcreate Random ly Initialized Ch a Ch a 7 5 3 9 Engine ( secure Random : ĠSecure Random ): ĠSk ipping Stream Cipher Ġ{ ĊĠ Ġval Ġengine Ġ= ĠCh a Ch a 7 5 3 9 Engine () ĊĠ Ġinit Cipher Random ly ( secure Random , Ġengine ) ĊĠ Ġreturn Ġengine Ċ } Ċ Ċ private Ġfun Ġinit Cipher Random ly ( secure Random : ĠSecure Random , Ġengine : ĠSk ipping Stream Cipher ) Ġ{ ĊĠ Ġval Ġkey Parameter Ġ= ĠKey Parameter ( secure Random . generate Bytes ( 3 2 )) ĊĠ Ġengine . init ( true , ĠParameters With IV ( key Parameter , Ġsecure Random . generate Bytes ( 1 2 ))) Ċ } Ċ Ċ // Ġwe Ġshould Ġon Ġeach Ġsave Ġchange Ġprotected Stream Key Ġfor Ġsecurity Ġreasons Ġ( as ĠK ee Web Ġalso Ġdoes ) Ċ // Ġso , Ġthis Ġrequirement Ġ( is Ġit Ġreally Ġrequired ?) Ġcan Ġforce Ġus Ġto Ġre - encrypt Ġall Ġpasswords Ġon Ġsave Ċ internal Ġclass ĠK ee Pass Database ( private Ġval Ġroot Element : ĠElement Ġ= Ġcreate Empty Database ()) Ġ{ ĊĠ Ġprivate Ġvar Ġsecure String Cipher Ġ= Ġlazy Ġ{ ĊĠĠĠ Ġcreate Random ly Initialized Ch a Ch a 7 5 3 9 Engine ( create Secure Random ()) ĊĠ Ġ} ĊĊĠ Ġ@ Volatile ĊĠ Ġvar Ġis Dirty : ĠBoolean Ġ= Ġfalse ĊĠĠĠ Ġinternal Ġset ĊĊĠ Ġval Ġroot Group : ĠK db x Group ĊĊĠ Ġinit Ġ{ ĊĠĠĠ Ġval Ġroot Element Ġ= Ġroot Element . get OrCreate ( K db x Db Element Names . root ) ĊĠĠĠ Ġval Ġgroup Element Ġ= Ġroot Element . getChild ( K db x Db Element Names . group ) ĊĠĠĠ Ġif Ġ( group Element Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠ Ġroot Group Ġ= Ġcreate Group ( this , Ġnull ) ĊĠĠĠĠĠ Ġroot Group . name Ġ= ĠK db x Db Element Names . root ĊĠĠĠĠĠ Ġroot Element . add Content ( root Group . element ) ĊĠĠĠ Ġ} ĊĠĠĠ Ġelse Ġ{ ĊĠĠĠĠĠ Ġroot Group Ġ= ĠK db x Group ( group Element , Ġthis , Ġnull ) ĊĠĠĠ Ġ} ĊĠ Ġ} ĊĊĠ Ġinternal Ġfun Ġprotect Value ( value : ĠCharSequence ) Ġ= ĠString Protected By Stream Cipher ( value , Ġsecure String Cipher . value ) ĊĊĠ Ġ@ Synchron ized ĊĠ Ġfun Ġsave ( credentials : ĠK ee Pass Credentials , ĠoutputStream : ĠOutputStream , Ġsecure Random : ĠSecure Random ) Ġ{ ĊĠĠĠ Ġval Ġk db x Header Ġ= ĠK db x Header ( secure Random ) ĊĠĠĠ Ġk db x Header . write K db x Header ( output Stream ) ĊĊĠĠĠ Ġval Ġmeta Element Ġ= Ġroot Element . get OrCreate (" Meta ") ĊĠĠĠ Ġmeta Element . get OrCreate (" Header Hash "). text Ġ= ĠBase 6 4 . get Encoder (). encode ToString ( k db x Header . header Hash ) ĊĠĠĠ Ġmeta Element . get OrCreate (" Memory Protection "). get OrCreate (" Protect Password "). text Ġ= Ġ" True " ĊĊĠĠĠ Ġk db x Header . create Encrypted Stream ( credentials . key , ĠoutputStream ). writer (). use Ġ{ ĊĠĠĠĠĠ ĠProtected Xml Writer ( create Sal sa 2 0 Stream Cipher ( k db x Header . protected Stream Key )). print Element ( it , Ġroot Element , Ġ 0 ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// Ġshould Ġwe Ġinit Ġsecure String Cipher Ġif Ġnow Ġwe Ġhave Ġsecure Random ? ĊĠĠĠ Ġ// Ġon Ġfirst Ġgl ance Ġyes , Ġbecause Ġcreating ĠSk ipping Stream Cipher Ġis Ġvery Ġfast Ġand Ġnot Ġmemory Ġh un gry , Ġand Ġcreating ĠSecure Random Ġis Ġa Ġcost Ġoperation , ĊĠĠĠ Ġ// Ġbut Ġno Ġ- Ġno Ġneed Ġto Ġinit Ġbecause Ġif Ġsave Ġcalled , Ġit Ġmeans Ġthat Ġdatabase Ġis Ġdirty Ġfor Ġsome Ġreasons Ġalready ... ĊĠĠĠ Ġ// Ġbut Ġyes Ġ- Ġbecause Ġmaybe Ġdatabase Ġis Ġdirty Ġdue Ġto Ġchange Ġsome Ġun protected Ġvalue Ġ( url , Ġuser Ġname ). ĊĠĠĠ Ġif Ġ( secure String Cipher . isInitialized ()) Ġ{ ĊĠĠĠĠĠ Ġinit Cipher Random ly ( secure Random , Ġsecure String Cipher . value ) ĊĠĠĠ Ġ} ĊĠĠĠ Ġelse Ġ{ ĊĠĠĠĠĠ Ġsecure String Cipher Ġ= Ġlazy Of ( create Random ly Initialized Ch a Ch a 7 5 3 9 Engine ( secure Random )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġis Dirty Ġ= Ġfalse ĊĠ Ġ} ĊĊĠ Ġfun Ġcreate Entry ( title : ĠString ): ĠK db x Entry Ġ{ ĊĠĠĠ Ġval Ġelement Ġ= ĠElement ( K db x Db Element Names . entry ) ĊĠĠĠ Ġensure Elements ( element , Ġmandatory Entry Elements ) ĊĊĠĠĠ Ġval Ġresult Ġ= ĠK db x Entry ( element , Ġthis , Ġnull ) ĊĠĠĠ Ġresult . title Ġ= Ġtitle ĊĠĠĠ Ġreturn Ġresult ĊĠ Ġ} Ċ } Ċ Ċ private Ġval Ġmandatory Entry Elements : ĠMap < Array < String >, ĠValue Creator > Ġ= Ġlinked Map Of ( ĊĠ ĠUUID _ ELEMENT _ NAME Ġto ĠU uid Value Creator (), ĊĠ ĠICON _ ELEMENT _ NAME Ġto ĠConstant Value Creator (" 0 "), ĊĠ ĠCRE ATION _ TIME _ ELEMENT _ NAME Ġto ĠDate Value Creator (), ĊĠ ĠLAST _ MO DIF ICATION _ TIME _ ELEMENT _ NAME Ġto ĠDate Value Creator (), ĊĠ ĠLAST _ ACCESS _ TIME _ ELEMENT _ NAME Ġto ĠDate Value Creator (), ĊĠ ĠEX PI RY _ TIME _ ELEMENT _ NAME Ġto ĠDate Value Creator (), ĊĠ ĠEX PI RES _ ELEMENT _ NAME Ġto ĠConstant Value Creator (" False "), ĊĠ ĠUS AGE _ COUNT _ ELEMENT _ NAME Ġto ĠConstant Value Creator (" 0 "), ĊĠ ĠLOC ATION _ CHANGED Ġto ĠDate Value Creator () Ċ ) Ċ Ċ internal Ġfun Ġensure Elements ( element : ĠElement , Ġchild Elements : ĠMap < Array < String >, ĠValue Creator >) Ġ{ ĊĠ Ġfor Ġ(( element Path , Ġvalue ) Ġin Ġchild Elements ) Ġ{ ĊĠĠĠ Ġval Ġresult Ġ= Ġfind Element ( element , Ġelement Path ) ĊĠĠĠ Ġif Ġ( result Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠ Ġvar Ġcurrent Element Ġ= Ġelement ĊĠĠĠĠĠ Ġfor Ġ( element Name Ġin Ġelement Path ) Ġ{ ĊĠĠĠĠĠĠĠ Ġcurrent Element Ġ= Ġcurrent Element . get OrCreate ( element Name ) ĊĠĠĠĠĠ Ġ} ĊĠĠĠĠĠ Ġcurrent Element . text Ġ= Ġvalue . value ĊĠĠĠ Ġ} ĊĠ Ġ} Ċ } Ċ Ċ private Ġfun Ġfind Element ( element : ĠElement , Ġelement Path : ĠArray < String >): ĠElement ? Ġ{ ĊĠ Ġvar Ġresult Ġ= Ġelement ĊĠ Ġfor Ġ( element Name Ġin Ġelement Path ) Ġ{ ĊĠĠĠ Ġresult Ġ= Ġresult . getChild ( element Name ) Ġ?: Ġreturn Ġnull ĊĠ Ġ} ĊĠ Ġreturn Ġresult Ċ } Ċ Ċ internal Ġfun Ġformatted Now () Ġ= ĠLocalDateTime . now ( Zone Offset . UTC ). format ( date Formatter ) Ċ Ċ internal Ġinterface ĠValue Creator Ġ{ ĊĠ Ġval Ġvalue : ĠString Ċ } Ċ Ċ internal Ġclass ĠConstant Value Creator ( override Ġval Ġvalue : ĠString ) Ġ: ĠValue Creator Ċ Ċ internal Ġclass ĠDate Value Creator Ġ: ĠValue Creator Ġ{ ĊĠ Ġoverride Ġval Ġvalue : ĠString ĊĠĠĠ Ġget () Ġ= Ġformatted Now () Ċ } Ċ Ċ internal Ġclass ĠU uid Value Creator Ġ: ĠValue Creator Ġ{ ĊĠ Ġoverride Ġval Ġvalue : ĠString ĊĠĠĠ Ġget () Ġ= Ġbase 6 4 From Uuid ( UUID . randomUUID ()) Ċ } Ċ Ċ private Ġfun Ġbase 6 4 From Uuid ( uuid : ĠUUID ): ĠString Ġ{ ĊĠ Ġval Ġb Ġ= ĠByteBuffer . wrap ( ByteArray ( 1 6 )) ĊĠ Ġb . put Long ( uuid . most Sign ificant Bits ) ĊĠ Ġb . put Long ( uuid . least Sign ificant Bits ) ĊĠ Ġreturn ĠBase 6 4 . get Encoder (). encode ToString ( b . array ()) Ċ } Ċ Ċ private Ġfun Ġcreate Empty Database (): ĠElement Ġ{ ĊĠ Ġval Ġcreation Date Ġ= Ġformatted Now () ĊĠ Ġ@ Suppress (" Spell Checking Inspection ") ĊĠ Ġreturn Ġload Element (""" < K ee Pass File > ĊĠĠĠ Ġ< Meta > ĊĠĠĠĠĠ Ġ< Generator > IJ </ Generator > ĊĠĠĠĠĠ Ġ< Header Hash ></ Header Hash > ĊĠĠĠĠĠ Ġ< Database Name > New ĠDatabase </ Database Name > ĊĠĠĠĠĠ Ġ< Database Name Changed >${ creation Date }</ Database Name Changed > ĊĠĠĠĠĠ Ġ< Database Description > Empty ĠDatabase </ Database Description > ĊĠĠĠĠĠ Ġ< Database Description Changed >${ creation Date }</ Database Description Changed > ĊĠĠĠĠĠ Ġ< Default UserName /> ĊĠĠĠĠĠ Ġ< Default UserName Changed >${ creation Date }</ Default UserName Changed > ĊĠĠĠĠĠ Ġ< Maintenance History Days > 3 6 5 </ Maintenance History Days > ĊĠĠĠĠĠ Ġ< Color /> ĊĠĠĠĠĠ Ġ< Master Key Changed >${ creation Date }</ Master Key Changed > ĊĠĠĠĠĠ Ġ< Master Key Change Rec >- 1 </ Master Key Change Rec > ĊĠĠĠĠĠ Ġ< Master Key Change Force >- 1 </ Master Key Change Force > ĊĠĠĠĠĠ Ġ< Memory Protection > ĊĠĠĠĠĠĠĠĠĠ Ġ< Protect Title > False </ Protect Title > ĊĠĠĠĠĠĠĠĠĠ Ġ< Protect UserName > False </ Protect UserName > ĊĠĠĠĠĠĠĠĠĠ Ġ< Protect Password > True </ Protect Password > ĊĠĠĠĠĠĠĠĠĠ Ġ< Protect URL > False </ Protect URL > ĊĠĠĠĠĠĠĠĠĠ Ġ< Protect Notes > False </ Protect Notes > ĊĠĠĠĠĠ Ġ</ Memory Protection > ĊĠĠĠĠĠ Ġ< Custom Icons /> ĊĠĠĠĠĠ Ġ< Re cycle Bin Enabled > True </ Re cycle Bin Enabled > ĊĠĠĠĠĠ Ġ< Re cycle Bin UUID > AAAAAAAAAAAAAAAA AAAAAA == </ Re cycle Bin UUID > ĊĠĠĠĠĠ Ġ< Re cycle Bin Changed >${ creation Date }</ Re cycle Bin Changed > ĊĠĠĠĠĠ Ġ< Entry Templates Group > AAAAAAAAAAAAAAAA AAAAAA == </ Entry Templates Group > ĊĠĠĠĠĠ Ġ< Entry Templates Group Changed >${ creation Date }</ Entry Templates Group Changed > ĊĠĠĠĠĠ Ġ< Last Selected Group > AAAAAAAAAAAAAAAA AAAAAA == </ Last Selected Group > ĊĠĠĠĠĠ Ġ< Last Top Visible Group > AAAAAAAAAAAAAAAA AAAAAA == </ Last Top Visible Group > ĊĠĠĠĠĠ Ġ< History Max Items > 1 0 </ History Max Items > ĊĠĠĠĠĠ Ġ< History MaxSize > 6 2 9 1 4 5 6 </ History MaxSize > ĊĠĠĠĠĠ Ġ< Bin aries /> ĊĠĠĠĠĠ Ġ< Custom Data /> ĊĠĠĠ Ġ</ Meta > ĊĠ Ġ</ K ee Pass File > """) Ċ } Ċ Ċ internal Ġclass ĠString Protected By Stream Cipher ( value : ĠByteArray , Ġprivate Ġval Ġcipher : ĠSk ipping Stream Cipher ) Ġ: ĠSecure String Ġ{ ĊĠ Ġprivate Ġval Ġposition : ĠLong ĊĠ Ġprivate Ġval Ġdata : ĠByteArray ĊĊĠ Ġconstructor ( value : ĠCharSequence , Ġcipher : ĠSk ipping Stream Cipher ) Ġ: Ġthis ( Charsets . UTF _ 8 . encode ( Char Buffer . wrap ( value )). toByteArray (), Ġcipher ) ĊĊĠ Ġinit Ġ{ ĊĠĠĠ Ġvar Ġposition Ġ= Ġ 0 L ĊĠĠĠ Ġdata Ġ= ĠByteArray ( value . size ) ĊĠĠĠ Ġsynchronized ( cipher ) Ġ{ ĊĠĠĠĠĠ Ġposition Ġ= Ġcipher . position ĊĠĠĠĠĠ Ġcipher . process Bytes ( value , Ġ 0 , Ġvalue . size , Ġdata , Ġ 0 ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġthis . position Ġ= Ġposition ĊĠ Ġ} ĊĊĠ Ġoverride Ġfun Ġget ( clear able : ĠBoolean ) Ġ= ĠOne Time String ( getAs ByteArray (), Ġclear able Ġ= Ġclear able ) ĊĊĠ Ġfun Ġget As ByteArray (): ĠByteArray Ġ{ ĊĠĠĠ Ġval Ġvalue Ġ= ĠByteArray ( data . size ) ĊĠĠĠ Ġsynchronized ( cipher ) Ġ{ ĊĠĠĠĠĠ Ġcipher . seek To ( position ) ĊĠĠĠĠĠ Ġcipher . process Bytes ( data , Ġ 0 , Ġdata . size , Ġvalue , Ġ 0 ) ĊĠĠĠ Ġ} ĊĠĠĠ Ġreturn Ġvalue ĊĠ Ġ} Ċ }