mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-160341 secure implementation of joinData
This commit is contained in:
@@ -17,6 +17,8 @@ package com.intellij.credentialStore
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.io.toByteArray
|
||||
import java.nio.CharBuffer
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
|
||||
@@ -28,11 +30,23 @@ internal fun toOldKeyAsIdentity(hash: ByteArray) = CredentialAttributes("Intelli
|
||||
|
||||
fun toOldKey(requestor: Class<*>, userName: String) = CredentialAttributes("IntelliJ Platform", toOldKey(MessageDigest.getInstance("SHA-256").digest("${requestor.name}/$userName".toByteArray())))
|
||||
|
||||
fun joinData(user: String?, password: OneTimeString?): String? {
|
||||
fun joinData(user: String?, password: OneTimeString?): ByteArray? {
|
||||
if (user == null && password == null) {
|
||||
return null
|
||||
}
|
||||
return "${StringUtil.escapeChars(user.orEmpty(), '\\', '@')}${if (password == null) "" else "@$password"}"
|
||||
|
||||
val builder = StringBuilder(user.orEmpty())
|
||||
StringUtil.escapeChar(builder, '\\')
|
||||
StringUtil.escapeChar(builder, '@')
|
||||
if (password != null) {
|
||||
builder.append('@')
|
||||
password.appendTo(builder)
|
||||
}
|
||||
|
||||
val buffer = Charsets.UTF_8.encode(CharBuffer.wrap(builder))
|
||||
// clear password
|
||||
builder.setLength(0)
|
||||
return buffer.toByteArray()
|
||||
}
|
||||
|
||||
fun splitData(data: String?): Credentials? {
|
||||
@@ -78,4 +92,4 @@ private fun parseString(data: String, delimiter: Char): List<String> {
|
||||
}
|
||||
|
||||
// check isEmpty before
|
||||
fun Credentials.serialize() = joinData(userName, password)!!.toByteArray()
|
||||
fun Credentials.serialize() = joinData(userName, password)!!
|
||||
@@ -13,10 +13,13 @@ private const val SECRET_SCHEMA_NONE = 0
|
||||
private const val SECRET_SCHEMA_ATTRIBUTE_STRING = 0
|
||||
|
||||
// explicitly create pointer to be explicitly dispose it to avoid sensitive data in the memory
|
||||
internal fun stringPointer(data: ByteArray): DisposableMemory {
|
||||
internal fun stringPointer(data: ByteArray, clearInput: Boolean = false): DisposableMemory {
|
||||
val pointer = DisposableMemory(data.size + 1L)
|
||||
pointer.write(0, data, 0, data.size)
|
||||
pointer.setByte(data.size.toLong(), 0.toByte())
|
||||
if (clearInput) {
|
||||
data.fill(0)
|
||||
}
|
||||
return pointer
|
||||
}
|
||||
|
||||
@@ -74,7 +77,7 @@ internal class SecretCredentialStore(schemeName: String) : CredentialStore {
|
||||
return
|
||||
}
|
||||
|
||||
val passwordPointer = stringPointer(credentials!!.serialize())
|
||||
val passwordPointer = stringPointer(credentials!!.serialize(), true)
|
||||
checkError("secret_password_store_sync") { errorRef ->
|
||||
try {
|
||||
if (accountName == null) {
|
||||
|
||||
@@ -27,7 +27,7 @@ class CredentialSerializeTest {
|
||||
|
||||
private fun test(u: String?, p: String?, joined: String) {
|
||||
val pass = p?.let(::OneTimeString)
|
||||
assertThat(joinData(u, pass)).isEqualTo(joined)
|
||||
assertThat(joinData(u, pass)).isEqualTo(joined.toByteArray())
|
||||
assertThat(splitData(joined)).isEqualTo(Credentials(u, pass))
|
||||
}
|
||||
}
|
||||
@@ -127,4 +127,11 @@ class OneTimeString @JvmOverloads constructor(value: CharArray, offset: Int = 0,
|
||||
}
|
||||
return super.equals(other)
|
||||
}
|
||||
|
||||
fun appendTo(builder: StringBuilder) {
|
||||
if (consumed.get()) {
|
||||
throw Error("Already consumed")
|
||||
}
|
||||
builder.append(myChars, myStart, length)
|
||||
}
|
||||
}
|
||||
@@ -2135,7 +2135,7 @@ public class StringUtil extends StringUtilRt {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static void escapeChar(@NotNull final StringBuilder buf, final char character) {
|
||||
public static void escapeChar(@NotNull final StringBuilder buf, final char character) {
|
||||
int idx = 0;
|
||||
while ((idx = indexOf(buf, character, idx)) >= 0) {
|
||||
buf.insert(idx, "\\");
|
||||
|
||||
Reference in New Issue
Block a user