r184
r159
1[include(틀:유우리)]
r158
2[include(틀:스텔라이브)]
r163
3[include(틀:Aidenk/틀 모음, Aidenk=0)]
r85
4{{{#!wiki style="max-width: 500px; padding: 10px 0; border-radius: 20px; background: linear-gradient(to right, #ba9dff, #ba9dff); float: right; text-align: center"
r155
5||<-2><tablewidth=100%><table bgcolor=#fff,#1c1d1f><tablebordercolor=#ba9dff,#ba9dff><colcolor=#fff><color=#00d2ff> ||
r175
6||<-2><nopad>[youtube(EIii4EXsfsU)]||
r172
7||{{{#!folding 기존 사진 접기
r176
8[[파일:special gift of kanna.jpg|width=100%]][br][br][[파일:블아임.png|width=100%]][br][br][[파일:규리감.jpg|width=100%]][br][br][[파일:2025/09/27 유니버스 타비/리제 신의상 합방.jpg|width=100%]]}}}[br][[파일:클리셰 공식 단체 사진.jpg|width=100%]]||}}}
r56
9
r23
10[목차]
11[clearfix]
r167
12== 개요 ==
r168
13생방은 본지 몇개월 안된 유튜브로만 보던 1~2년차 파스텔. 초기의 시작은 강지와 김블루 우결. 그렇게 강지를 알게된후 칸나를 알게되어 이렇게 파스텔이 되었다 카더라.
r167
14
r177
15== 통포(10/27) ==
r176
16 1. 위: [[시라유키 히나]] 11,510개
17 1. 위: [[텐코 시부키]] 10,280개
r174
18 1. 위: [[아라하시 타비]] 1,680개
19 1. 위: [[아카네 리제]] 1,560
20 1. 위: [[유즈하 리코]] 1,190
21 1. 위: [[하나코 나나]] 970개
r176
22 1. 위: [[네네코 마시로]] 660개
r174
23 1. 위: [[사키하네 후야]] 590개
24 1. 위: [[아오쿠모 린]] 460개
25 1. 위: [[아야츠노 유니]] 310개
26 1. 위: [[강지]] 300개
r167
27
r170
28파스텔이라고 모든 방송을 다 보는것이 아니다. 사실상 7위 아래로는 거의 안본다. 유튜브도 이런거 만들어야한다.
r169
29
r135
30== 방송 역사 작성 요령 ==
r150
31간단합니다. 치지직에서 생방을 보면됩니다. 히나, 부키는 거기다가 방송에서 노래랑 피아노를 자주 쳐주고 불러주기에 힐링됩니다. 힐링 방송을 원하시다면 파스텔 또는 이나리, 해둥이가 되세요! 새벽 4시에 키는게 어디있냐고! 아... 자고싶다... 아닛! 휴대폰 키고 자버려서 노래방 못봤다...
r135
32
r143
33가끔 x 또는 카페의 방송 후기나 기록을 가지고 작성합니다. 유니, 타비, 시로, 리제, 린, 나나, 리코는 작성이 쉽습니다. 하지만 부키, 히나는 작성이 힘듭니다.
34히나는 "안자는 해둥이 있나요"는 새벽 3시에 끝나서 작성하기 힘듭니다. 하지만 저는 작성하죠 ㅎㅎ 부키는 평균 방송 시간 7시간 거의 새벽까지 방송하기에 히나와 비슷하게 새벽 3시까지는 깨어있어야합니다.
35
r156
36Aidenk의 노가다를 보기 -> [[사용자:Aidenk/연습장]]
r143
37
r147
38Aidenk의 버츄얼 수필을 보기 -> [[사용자:Aidenk/버츄얼]]
39
r23
40== 개요 ==
r140
41해둥이 주글께! - 해둥이 -
r139
42
r120
43주석은 혁명이야!
r119
44
r157
45[[스텔라이브]] 실시간 업데이트 중이진 않음
r145
463기생 사진 준비중 ...
r119
47
r118
48직접 곡을 들으며 starr, end 시간대를 찾는 편집으로 힐링하는 사람. 편집도 하고 노래도 듣고 생방도 보고 너무 좋잖아!
r113
49
r161
50[[나무위키]]의 [[https://namu.wiki/w/%EC%82%AC%EC%9A%A9%EC%9E%90:Aidenk|Aidenk]], [[https://namu.wiki/w/%EC%82%AC%EC%9A%A9%EC%9E%90:Airi_Kanna|Airi_Kanna]], [[https://namu.wiki/w/%EC%82%AC%EC%9A%A9%EC%9E%90:Hebi|Hebi^^{{{-3 봇계정}}}^^]] 와 동일인. 더시드위키의 [[사용자:Tenko_Shibuki]], [[사용자:Shirayuki_Hina]]와 동일인.
r98
51프로필 사진 너무 예쁜데... 예쁘고 귀여우니... 별찜좀...
52
r146
53이나리로 전향한듯 한 해둥이(?)가 아닌데 이나리인데 해둥이. 근데 바람은 아님(?)
r125
54음 그니깐... 쨋든 파스텔.
r105
55
r106
56[[/연습장|{{{#!wiki style="display: inline; color: transparent; background: text linear-gradient(to right, #f58abb, #fed09f)"
r182
57'''연습장 바로가기'''}}}]]
58
r184
59
60== csharp 암호화 코드 ==
61오류가 많을 예정(ai 작성).
62
r182
63{{{#!syntax csharp
64using System;
65using System.IO;
66using System.Security.Cryptography;
67using System.Text;
68using UnityEngine;
69using System.Diagnostics;
70using System.Runtime.CompilerServices;
71
72[Serializable]
73public class PlayerData
74{
75 public string playerName;
76 public int score;
77}
78
79public class SecureManager : MonoBehaviour
80{
81 public static SecureManager Instance { get; private set; }
82
83 public bool EnableHardening = true;
84 public bool EnableAntiDebugChecks = true;
85 public bool EnableRootDetection = true;
86 public bool EnableDummyMix = true;
87 public bool EnableFileNameObfuscation = true;
88 public bool EnableRotation = true;
89
90 private const string Magic = "SJMP";
91 private const byte Version = 1;
92 private const int SaltLenDefault = 12;
93 private const int IvLen = 16;
94 private const int HmacLen = 32;
95 private const int KeyMaterialLen = 64;
96 private const int AesKeyLen = 32;
97 private const int HmacKeyLen = 32;
98 private const int Pbkdf2Iterations = 20000;
99 private readonly byte[] obfPartA = new byte[] { 0x4A, 0x5F, 0x33, 0x29, 0x11, 0x7C, 0x6D, 0x3E, 0x2D, 0x7A, 0x5B, 0x1C };
100 private readonly byte[] obfPartB = new byte[] { 0x91, 0x20, 0x55, 0x12, 0x44, 0x38, 0x77, 0x0A, 0x6F, 0x21, 0x9D, 0xEE };
101 private const byte Mask = 0xAA;
102 private string filePath;
103 private byte[] sessionNonce;
104
105 void Awake()
106 {
107 if (Instance != null && Instance != this)
108 {
109 Destroy(gameObject);
110 return;
111 }
112 Instance = this;
113 DontDestroyOnLoad(gameObject);
114
115 sessionNonce = GenerateRandomBytes(16);
116 filePath = Path.Combine(Application.persistentDataPath, ResolveFileName("playerData"));
117 Warmup();
118 }
119
120 private void Warmup()
121 {
122 try { _ = GetSecretBytes(); } catch { }
123 }
124
125 [MethodImpl(MethodImplOptions.NoInlining)]
126 private byte[] DumbMixA(byte[] input)
127 {
128 byte[] outb = new byte[input.Length];
129 for (int i = 0; i < input.Length; i++)
130 {
131 int v = input[i];
132 v = ((v << 3) | (v >> 5)) & 0xFF;
133 v ^= (i * 37) & 0xFF;
134 outb[i] = (byte)v;
135 }
136 return outb;
137 }
138
139 [MethodImpl(MethodImplOptions.NoInlining)]
140 private byte[] DumbMixB(byte[] input, int seed)
141 {
142 byte[] outb = new byte[input.Length];
143 for (int i = 0; i < input.Length; i++)
144 {
145 int v = input[i] ^ (seed >> (i % 8));
146 v = (v * 13 + (i * 7)) & 0xFF;
147 v = (v ^ 0x5A) & 0xFF;
148 outb[i] = (byte)v;
149 }
150 return outb;
151 }
152
153 [MethodImpl(MethodImplOptions.NoInlining)]
154 private byte[] DumbMixC(byte[] input, byte[] nonce)
155 {
156 byte[] outb = new byte[input.Length];
157 for (int i = 0; i < input.Length; i++)
158 {
159 int n = nonce[i % nonce.Length];
160 int v = input[i];
161 v = ((v + n) ^ (n >> (i % 4))) & 0xFF;
162 outb[i] = (byte)v;
163 }
164 return outb;
165 }
166
167 private byte[] GetSecretBytes()
168 {
169 byte[] k = new byte[obfPartA.Length + obfPartB.Length];
170 for (int i = 0; i < obfPartA.Length; i++) k[i] = (byte)(obfPartA[i] ^ Mask);
171 for (int i = 0; i < obfPartB.Length; i++) k[i + obfPartA.Length] = (byte)(obfPartB[i] ^ Mask);
172
173 if (!EnableHardening || !EnableDummyMix)
174 {
175 byte[] simple = new byte[k.Length];
176 Buffer.BlockCopy(k, 0, simple, 0, k.Length);
177 Array.Clear(k, 0, k.Length);
178 return simple;
179 }
180
181 byte[] s1 = DumbMixA(k);
182 int dynamicSeed = (int)(DateTime.UtcNow.Ticks ^ Application.identifier.GetHashCode() ^ Environment.TickCount);
183 byte[] s2 = DumbMixB(s1, dynamicSeed);
184 byte[] s3 = DumbMixC(s2, sessionNonce);
185 for (int r = 0; r < 2; r++)
186 {
187 byte[] t = DumbMixA(s3);
188 byte[] u = DumbMixB(t, dynamicSeed ^ r);
189 for (int i = 0; i < k.Length; i++) s3[i] = (byte)(s3[i] ^ u[i % u.Length]);
190 Array.Clear(t, 0, t.Length);
191 Array.Clear(u, 0, u.Length);
192 }
193 Array.Clear(s1, 0, s1.Length);
194 Array.Clear(s2, 0, s2.Length);
195 byte[] result = new byte[k.Length];
196 for (int i = 0; i < k.Length; i++) result[i] = (byte)(k[i] ^ s3[i % s3.Length]);
197 Array.Clear(k, 0, k.Length);
198 Array.Clear(s3, 0, s3.Length);
199 return result;
200 }
201
202 private (byte[] aesKey, byte[] hmacKey) DeriveKeysRotating(byte[] salt, byte[] rotationNonce)
203 {
204 byte[] secret = GetSecretBytes();
205 string secretStr = EnableHardening ? Convert.ToBase64String(secret) + Application.identifier : Encoding.UTF8.GetString(secret) + Application.identifier;
206 Array.Clear(secret, 0, secret.Length);
207
208 using (var kdf = new Rfc2898DeriveBytes(secretStr, salt, Pbkdf2Iterations, HashAlgorithmName.SHA256))
209 {
210 byte[] km = kdf.GetBytes(KeyMaterialLen);
211 if (EnableHardening && EnableRotation && rotationNonce != null)
212 {
213 for (int i = 0; i < km.Length; i++) km[i] ^= rotationNonce[i % rotationNonce.Length];
214 }
215 byte[] aesKey = new byte[AesKeyLen];
216 byte[] hmacKey = new byte[HmacKeyLen];
217 Buffer.BlockCopy(km, 0, aesKey, 0, AesKeyLen);
218 Buffer.BlockCopy(km, AesKeyLen, hmacKey, 0, HmacKeyLen);
219 Array.Clear(km, 0, km.Length);
220 return (aesKey, hmacKey);
221 }
222 }
223
224 public void Save<T>(T data)
225 {
226 if (EnableHardening && (EnableAntiDebugChecks || EnableRootDetection) && IsTamperedOrDebug()) return;
227 try
228 {
229 string json = JsonUtility.ToJson(data);
230 byte[] salt = GenerateRandomBytes(SaltLenDefault);
231 byte[] rotation = (EnableHardening && EnableRotation) ? GenerateRandomBytes(16) : new byte[16];
232 var keys = DeriveKeysRotating(salt, (EnableRotation ? rotation : null));
233 byte[] aesKey = keys.aesKey;
234 byte[] hmacKey = keys.hmacKey;
235 byte[] plain = Encoding.UTF8.GetBytes(json);
236 byte[] iv;
237 byte[] cipher;
238 using (Aes aes = Aes.Create())
239 {
240 aes.KeySize = 256;
241 aes.Mode = CipherMode.CBC;
242 aes.Padding = PaddingMode.PKCS7;
243 aes.Key = aesKey;
244 aes.GenerateIV();
245 iv = aes.IV;
246 using (var enc = aes.CreateEncryptor(aes.Key, iv))
247 cipher = enc.TransformFinalBlock(plain, 0, plain.Length);
248 }
249 byte[] ivCipher = new byte[iv.Length + cipher.Length];
250 Buffer.BlockCopy(iv, 0, ivCipher, 0, iv.Length);
251 Buffer.BlockCopy(cipher, 0, ivCipher, iv.Length, cipher.Length);
252 byte[] hmac;
253 using (var h = new HMACSHA256(hmacKey)) hmac = h.ComputeHash(ivCipher);
254 using (MemoryStream ms = new MemoryStream())
255 {
256 ms.Write(Encoding.ASCII.GetBytes(Magic), 0, 4);
257 ms.WriteByte(Version);
258 ms.WriteByte((byte)salt.Length);
259 ms.Write(salt, 0, salt.Length);
260 ms.WriteByte(EnableRotation ? (byte)rotation.Length : (byte)0);
261 if (EnableRotation) ms.Write(rotation, 0, rotation.Length);
262 ms.Write(iv, 0, iv.Length);
263 byte[] cipherLenBytes = BitConverter.GetBytes((Int32)cipher.Length);
264 if (!BitConverter.IsLittleEndian) Array.Reverse(cipherLenBytes);
265 ms.Write(cipherLenBytes, 0, 4);
266 ms.Write(cipher, 0, cipher.Length);
267 ms.Write(hmac, 0, hmac.Length);
268 string outBlob = Convert.ToBase64String(ms.ToArray());
269 File.WriteAllText(filePath, outBlob);
270 }
271 ClearBytes(aesKey);
272 ClearBytes(hmacKey);
273 ClearBytes(plain);
274 ClearBytes(iv);
275 ClearBytes(cipher);
276 ClearBytes(ivCipher);
277 ClearBytes(hmac);
278 ClearBytes(salt);
279 ClearBytes(rotation);
280 }
281 catch { }
282 }
283
284 public T Load<T>()
285 {
286 if (EnableHardening && (EnableAntiDebugChecks || EnableRootDetection) && IsTamperedOrDebug()) return default;
287 if (!File.Exists(filePath)) return default;
288 string blob = File.ReadAllText(filePath);
289 byte[] total;
290 try { total = Convert.FromBase64String(blob); } catch { return default; }
291 try
292 {
293 using (MemoryStream ms = new MemoryStream(total))
294 using (BinaryReader br = new BinaryReader(ms))
295 {
296 byte[] magic = br.ReadBytes(4);
297 if (Encoding.ASCII.GetString(magic) != Magic) return default;
298 byte ver = br.ReadByte();
299 if (ver != Version) return default;
300 int saltLen = br.ReadByte();
301 if (saltLen <= 0 || saltLen > 64) return default;
302 byte[] salt = br.ReadBytes(saltLen);
303 int rotationLen = br.ReadByte();
304 byte[] rotation = rotationLen > 0 ? br.ReadBytes(rotationLen) : new byte[16];
305 byte[] iv = br.ReadBytes(IvLen);
306 int cipherLen = br.ReadInt32();
307 if (!BitConverter.IsLittleEndian) cipherLen = System.Net.IPAddress.NetworkToHostOrder(cipherLen);
308 if (cipherLen <= 0 || cipherLen > total.Length) return default;
309 byte[] cipher = br.ReadBytes(cipherLen);
310 byte[] hmac = br.ReadBytes(HmacLen);
311 byte[] ivCipher = new byte[iv.Length + cipher.Length];
312 Buffer.BlockCopy(iv, 0, ivCipher, 0, iv.Length);
313 Buffer.BlockCopy(cipher, 0, ivCipher, iv.Length, cipher.Length);
314 var keys = DeriveKeysRotating(salt, (EnableRotation ? rotation : null));
315 byte[] aesKey = keys.aesKey;
316 byte[] hmacKey = keys.hmacKey;
317 byte[] expected;
318 using (var h = new HMACSHA256(hmacKey)) expected = h.ComputeHash(ivCipher);
319 bool ok = CryptographicOperations.FixedTimeEquals(expected, hmac);
320 if (!ok)
321 {
322 ClearBytes(aesKey);
323 ClearBytes(hmacKey);
324 ClearBytes(expected);
325 return default;
326 }
327 byte[] plain;
328 using (Aes aes = Aes.Create())
329 {
330 aes.KeySize = 256;
331 aes.Mode = CipherMode.CBC;
332 aes.Padding = PaddingMode.PKCS7;
333 aes.Key = aesKey;
334 aes.IV = iv;
335 using (var dec = aes.CreateDecryptor(aes.Key, aes.IV))
336 plain = dec.TransformFinalBlock(cipher, 0, cipher.Length);
337 }
338 string json = Encoding.UTF8.GetString(plain);
339 ClearBytes(aesKey);
340 ClearBytes(hmacKey);
341 ClearBytes(expected);
342 ClearBytes(plain);
343 ClearBytes(iv);
344 ClearBytes(cipher);
345 ClearBytes(salt);
346 ClearBytes(rotation);
347 return JsonUtility.FromJson<T>(json);
348 }
349 }
350 catch { return default; }
351 }
352
353 private static byte[] GenerateRandomBytes(int len)
354 {
355 byte[] b = new byte[len];
356 using (var rng = RandomNumberGenerator.Create()) rng.GetBytes(b);
357 return b;
358 }
359
360 private static void ClearBytes(byte[] b)
361 {
362 if (b == null) return;
363 Array.Clear(b, 0, b.Length);
364 }
365
366 private string ResolveFileName(string baseName)
367 {
368 if (!EnableHardening || !EnableFileNameObfuscation) return baseName + ".dat";
369 byte[] nameBytes = Encoding.UTF8.GetBytes(baseName + Application.identifier);
370 using (var sha = SHA256.Create())
371 {
372 byte[] hash = sha.ComputeHash(nameBytes);
373 string b64 = Convert.ToBase64String(hash);
374 string safe = b64.Replace('+', '-').Replace('/', '_').Replace('=', 'x');
375 ClearBytes(hash);
376 return safe.Substring(0, Math.Min(28, safe.Length)) + ".dat";
377 }
378 }
379
380 private bool IsTamperedOrDebug()
381 {
382 if (!EnableHardening) return false;
383 try
384 {
385 if (EnableAntiDebugChecks)
386 {
387 if (Debug.isDebugBuild) return true;
388 if (Debugger.IsAttached) return true;
389 }
390 }
391 catch { }
392 try
393 {
394 if (EnableRootDetection)
395 {
396 string[] suspectPaths = new string[] { "/system/bin/su", "/system/xbin/su", "/sbin/su" };
397 foreach (var p in suspectPaths) if (File.Exists(p)) return true;
398 }
399 }
400 catch { }
401 return false;
402 }
r183
403} }}}
404
405{{{#!syntax csharp
406using UnityEngine;
407
408public class ExampleUsage : MonoBehaviour
409{
410 private readonly string testPlayerName = "Gemini_Test_User";
411 private readonly int initialScore = 1000;
412 private readonly int newScore = 5000;
413
414 void Start()
415 {
416 if (SecureManager.Instance == null)
417 {
418 Debug.LogError("SecureManager 인스턴스를 찾을 수 없습니다. SecureManager.cs를 GameObject에 추가했는지 확인해주세요.");
419 return;
420 }
421 SaveTestData();
422
423 LoadTestData();
424
425 UpdateAndSaveTestData();
426
427 LoadTestData();
428 }
429
430 void SaveTestData()
431 {
432 Debug.Log("--- 1. 초기 데이터 저장 시도 ---");
433 PlayerData dataToSave = new PlayerData
434 {
435 playerName = testPlayerName,
436 score = initialScore
437 };
438
439 SecureManager.Instance.Save(dataToSave);
440 Debug.Log($"초기 데이터 저장 완료: Player={dataToSave.playerName}, Score={dataToSave.score}");
441 }
442
443 void LoadTestData()
444 {
445 Debug.Log("--- 2. 데이터 로드 시도 ---");
446 PlayerData loadedData = SecureManager.Instance.Load<PlayerData>();
447
448 if (loadedData != null)
449 {
450 Debug.Log($"데이터 로드 성공: Player={loadedData.playerName}, Score={loadedData.score}");
451 }
452 else
453 {
454 Debug.LogWarning("데이터 로드 실패 (파일 없음, 오류 발생, 혹은 디버거 감지).");
455 }
456 }
457
458 void UpdateAndSaveTestData()
459 {
460 Debug.Log("--- 3. 데이터 업데이트 및 재저장 시도 ---");
461 PlayerData loadedData = SecureManager.Instance.Load<PlayerData>();
462
463 if (loadedData != null)
464 {
465 loadedData.score = newScore;
466 SecureManager.Instance.Save(loadedData);
467 Debug.Log($"데이터 업데이트 및 저장 완료: New Score={loadedData.score}");
468 }
469 }
470
471 void OnDestroy()
472 {
473 if (SecureManager.Instance != null && SecureManager.Instance.EnableAntiDebugChecks)
474 {
475 Debug.Log("SecureManager: Anti-Debug Checks가 활성화되어 있습니다.");
476 }
477 }
r182
478} }}}