r182
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
59{{{#!syntax csharp
60using System;
61using System.IO;
62using System.Security.Cryptography;
63using System.Text;
64using UnityEngine;
65using System.Diagnostics;
66using System.Runtime.CompilerServices;
67
68[Serializable]
69public class PlayerData
70{
71 public string playerName;
72 public int score;
73}
74
75public class SecureManager : MonoBehaviour
76{
77 public static SecureManager Instance { get; private set; }
78
79 public bool EnableHardening = true;
80 public bool EnableAntiDebugChecks = true;
81 public bool EnableRootDetection = true;
82 public bool EnableDummyMix = true;
83 public bool EnableFileNameObfuscation = true;
84 public bool EnableRotation = true;
85
86 private const string Magic = "SJMP";
87 private const byte Version = 1;
88 private const int SaltLenDefault = 12;
89 private const int IvLen = 16;
90 private const int HmacLen = 32;
91 private const int KeyMaterialLen = 64;
92 private const int AesKeyLen = 32;
93 private const int HmacKeyLen = 32;
94 private const int Pbkdf2Iterations = 20000;
95 private readonly byte[] obfPartA = new byte[] { 0x4A, 0x5F, 0x33, 0x29, 0x11, 0x7C, 0x6D, 0x3E, 0x2D, 0x7A, 0x5B, 0x1C };
96 private readonly byte[] obfPartB = new byte[] { 0x91, 0x20, 0x55, 0x12, 0x44, 0x38, 0x77, 0x0A, 0x6F, 0x21, 0x9D, 0xEE };
97 private const byte Mask = 0xAA;
98 private string filePath;
99 private byte[] sessionNonce;
100
101 void Awake()
102 {
103 if (Instance != null && Instance != this)
104 {
105 Destroy(gameObject);
106 return;
107 }
108 Instance = this;
109 DontDestroyOnLoad(gameObject);
110
111 sessionNonce = GenerateRandomBytes(16);
112 filePath = Path.Combine(Application.persistentDataPath, ResolveFileName("playerData"));
113 Warmup();
114 }
115
116 private void Warmup()
117 {
118 try { _ = GetSecretBytes(); } catch { }
119 }
120
121 [MethodImpl(MethodImplOptions.NoInlining)]
122 private byte[] DumbMixA(byte[] input)
123 {
124 byte[] outb = new byte[input.Length];
125 for (int i = 0; i < input.Length; i++)
126 {
127 int v = input[i];
128 v = ((v << 3) | (v >> 5)) & 0xFF;
129 v ^= (i * 37) & 0xFF;
130 outb[i] = (byte)v;
131 }
132 return outb;
133 }
134
135 [MethodImpl(MethodImplOptions.NoInlining)]
136 private byte[] DumbMixB(byte[] input, int seed)
137 {
138 byte[] outb = new byte[input.Length];
139 for (int i = 0; i < input.Length; i++)
140 {
141 int v = input[i] ^ (seed >> (i % 8));
142 v = (v * 13 + (i * 7)) & 0xFF;
143 v = (v ^ 0x5A) & 0xFF;
144 outb[i] = (byte)v;
145 }
146 return outb;
147 }
148
149 [MethodImpl(MethodImplOptions.NoInlining)]
150 private byte[] DumbMixC(byte[] input, byte[] nonce)
151 {
152 byte[] outb = new byte[input.Length];
153 for (int i = 0; i < input.Length; i++)
154 {
155 int n = nonce[i % nonce.Length];
156 int v = input[i];
157 v = ((v + n) ^ (n >> (i % 4))) & 0xFF;
158 outb[i] = (byte)v;
159 }
160 return outb;
161 }
162
163 private byte[] GetSecretBytes()
164 {
165 byte[] k = new byte[obfPartA.Length + obfPartB.Length];
166 for (int i = 0; i < obfPartA.Length; i++) k[i] = (byte)(obfPartA[i] ^ Mask);
167 for (int i = 0; i < obfPartB.Length; i++) k[i + obfPartA.Length] = (byte)(obfPartB[i] ^ Mask);
168
169 if (!EnableHardening || !EnableDummyMix)
170 {
171 byte[] simple = new byte[k.Length];
172 Buffer.BlockCopy(k, 0, simple, 0, k.Length);
173 Array.Clear(k, 0, k.Length);
174 return simple;
175 }
176
177 byte[] s1 = DumbMixA(k);
178 int dynamicSeed = (int)(DateTime.UtcNow.Ticks ^ Application.identifier.GetHashCode() ^ Environment.TickCount);
179 byte[] s2 = DumbMixB(s1, dynamicSeed);
180 byte[] s3 = DumbMixC(s2, sessionNonce);
181 for (int r = 0; r < 2; r++)
182 {
183 byte[] t = DumbMixA(s3);
184 byte[] u = DumbMixB(t, dynamicSeed ^ r);
185 for (int i = 0; i < k.Length; i++) s3[i] = (byte)(s3[i] ^ u[i % u.Length]);
186 Array.Clear(t, 0, t.Length);
187 Array.Clear(u, 0, u.Length);
188 }
189 Array.Clear(s1, 0, s1.Length);
190 Array.Clear(s2, 0, s2.Length);
191 byte[] result = new byte[k.Length];
192 for (int i = 0; i < k.Length; i++) result[i] = (byte)(k[i] ^ s3[i % s3.Length]);
193 Array.Clear(k, 0, k.Length);
194 Array.Clear(s3, 0, s3.Length);
195 return result;
196 }
197
198 private (byte[] aesKey, byte[] hmacKey) DeriveKeysRotating(byte[] salt, byte[] rotationNonce)
199 {
200 byte[] secret = GetSecretBytes();
201 string secretStr = EnableHardening ? Convert.ToBase64String(secret) + Application.identifier : Encoding.UTF8.GetString(secret) + Application.identifier;
202 Array.Clear(secret, 0, secret.Length);
203
204 using (var kdf = new Rfc2898DeriveBytes(secretStr, salt, Pbkdf2Iterations, HashAlgorithmName.SHA256))
205 {
206 byte[] km = kdf.GetBytes(KeyMaterialLen);
207 if (EnableHardening && EnableRotation && rotationNonce != null)
208 {
209 for (int i = 0; i < km.Length; i++) km[i] ^= rotationNonce[i % rotationNonce.Length];
210 }
211 byte[] aesKey = new byte[AesKeyLen];
212 byte[] hmacKey = new byte[HmacKeyLen];
213 Buffer.BlockCopy(km, 0, aesKey, 0, AesKeyLen);
214 Buffer.BlockCopy(km, AesKeyLen, hmacKey, 0, HmacKeyLen);
215 Array.Clear(km, 0, km.Length);
216 return (aesKey, hmacKey);
217 }
218 }
219
220 public void Save<T>(T data)
221 {
222 if (EnableHardening && (EnableAntiDebugChecks || EnableRootDetection) && IsTamperedOrDebug()) return;
223 try
224 {
225 string json = JsonUtility.ToJson(data);
226 byte[] salt = GenerateRandomBytes(SaltLenDefault);
227 byte[] rotation = (EnableHardening && EnableRotation) ? GenerateRandomBytes(16) : new byte[16];
228 var keys = DeriveKeysRotating(salt, (EnableRotation ? rotation : null));
229 byte[] aesKey = keys.aesKey;
230 byte[] hmacKey = keys.hmacKey;
231 byte[] plain = Encoding.UTF8.GetBytes(json);
232 byte[] iv;
233 byte[] cipher;
234 using (Aes aes = Aes.Create())
235 {
236 aes.KeySize = 256;
237 aes.Mode = CipherMode.CBC;
238 aes.Padding = PaddingMode.PKCS7;
239 aes.Key = aesKey;
240 aes.GenerateIV();
241 iv = aes.IV;
242 using (var enc = aes.CreateEncryptor(aes.Key, iv))
243 cipher = enc.TransformFinalBlock(plain, 0, plain.Length);
244 }
245 byte[] ivCipher = new byte[iv.Length + cipher.Length];
246 Buffer.BlockCopy(iv, 0, ivCipher, 0, iv.Length);
247 Buffer.BlockCopy(cipher, 0, ivCipher, iv.Length, cipher.Length);
248 byte[] hmac;
249 using (var h = new HMACSHA256(hmacKey)) hmac = h.ComputeHash(ivCipher);
250 using (MemoryStream ms = new MemoryStream())
251 {
252 ms.Write(Encoding.ASCII.GetBytes(Magic), 0, 4);
253 ms.WriteByte(Version);
254 ms.WriteByte((byte)salt.Length);
255 ms.Write(salt, 0, salt.Length);
256 ms.WriteByte(EnableRotation ? (byte)rotation.Length : (byte)0);
257 if (EnableRotation) ms.Write(rotation, 0, rotation.Length);
258 ms.Write(iv, 0, iv.Length);
259 byte[] cipherLenBytes = BitConverter.GetBytes((Int32)cipher.Length);
260 if (!BitConverter.IsLittleEndian) Array.Reverse(cipherLenBytes);
261 ms.Write(cipherLenBytes, 0, 4);
262 ms.Write(cipher, 0, cipher.Length);
263 ms.Write(hmac, 0, hmac.Length);
264 string outBlob = Convert.ToBase64String(ms.ToArray());
265 File.WriteAllText(filePath, outBlob);
266 }
267 ClearBytes(aesKey);
268 ClearBytes(hmacKey);
269 ClearBytes(plain);
270 ClearBytes(iv);
271 ClearBytes(cipher);
272 ClearBytes(ivCipher);
273 ClearBytes(hmac);
274 ClearBytes(salt);
275 ClearBytes(rotation);
276 }
277 catch { }
278 }
279
280 public T Load<T>()
281 {
282 if (EnableHardening && (EnableAntiDebugChecks || EnableRootDetection) && IsTamperedOrDebug()) return default;
283 if (!File.Exists(filePath)) return default;
284 string blob = File.ReadAllText(filePath);
285 byte[] total;
286 try { total = Convert.FromBase64String(blob); } catch { return default; }
287 try
288 {
289 using (MemoryStream ms = new MemoryStream(total))
290 using (BinaryReader br = new BinaryReader(ms))
291 {
292 byte[] magic = br.ReadBytes(4);
293 if (Encoding.ASCII.GetString(magic) != Magic) return default;
294 byte ver = br.ReadByte();
295 if (ver != Version) return default;
296 int saltLen = br.ReadByte();
297 if (saltLen <= 0 || saltLen > 64) return default;
298 byte[] salt = br.ReadBytes(saltLen);
299 int rotationLen = br.ReadByte();
300 byte[] rotation = rotationLen > 0 ? br.ReadBytes(rotationLen) : new byte[16];
301 byte[] iv = br.ReadBytes(IvLen);
302 int cipherLen = br.ReadInt32();
303 if (!BitConverter.IsLittleEndian) cipherLen = System.Net.IPAddress.NetworkToHostOrder(cipherLen);
304 if (cipherLen <= 0 || cipherLen > total.Length) return default;
305 byte[] cipher = br.ReadBytes(cipherLen);
306 byte[] hmac = br.ReadBytes(HmacLen);
307 byte[] ivCipher = new byte[iv.Length + cipher.Length];
308 Buffer.BlockCopy(iv, 0, ivCipher, 0, iv.Length);
309 Buffer.BlockCopy(cipher, 0, ivCipher, iv.Length, cipher.Length);
310 var keys = DeriveKeysRotating(salt, (EnableRotation ? rotation : null));
311 byte[] aesKey = keys.aesKey;
312 byte[] hmacKey = keys.hmacKey;
313 byte[] expected;
314 using (var h = new HMACSHA256(hmacKey)) expected = h.ComputeHash(ivCipher);
315 bool ok = CryptographicOperations.FixedTimeEquals(expected, hmac);
316 if (!ok)
317 {
318 ClearBytes(aesKey);
319 ClearBytes(hmacKey);
320 ClearBytes(expected);
321 return default;
322 }
323 byte[] plain;
324 using (Aes aes = Aes.Create())
325 {
326 aes.KeySize = 256;
327 aes.Mode = CipherMode.CBC;
328 aes.Padding = PaddingMode.PKCS7;
329 aes.Key = aesKey;
330 aes.IV = iv;
331 using (var dec = aes.CreateDecryptor(aes.Key, aes.IV))
332 plain = dec.TransformFinalBlock(cipher, 0, cipher.Length);
333 }
334 string json = Encoding.UTF8.GetString(plain);
335 ClearBytes(aesKey);
336 ClearBytes(hmacKey);
337 ClearBytes(expected);
338 ClearBytes(plain);
339 ClearBytes(iv);
340 ClearBytes(cipher);
341 ClearBytes(salt);
342 ClearBytes(rotation);
343 return JsonUtility.FromJson<T>(json);
344 }
345 }
346 catch { return default; }
347 }
348
349 private static byte[] GenerateRandomBytes(int len)
350 {
351 byte[] b = new byte[len];
352 using (var rng = RandomNumberGenerator.Create()) rng.GetBytes(b);
353 return b;
354 }
355
356 private static void ClearBytes(byte[] b)
357 {
358 if (b == null) return;
359 Array.Clear(b, 0, b.Length);
360 }
361
362 private string ResolveFileName(string baseName)
363 {
364 if (!EnableHardening || !EnableFileNameObfuscation) return baseName + ".dat";
365 byte[] nameBytes = Encoding.UTF8.GetBytes(baseName + Application.identifier);
366 using (var sha = SHA256.Create())
367 {
368 byte[] hash = sha.ComputeHash(nameBytes);
369 string b64 = Convert.ToBase64String(hash);
370 string safe = b64.Replace('+', '-').Replace('/', '_').Replace('=', 'x');
371 ClearBytes(hash);
372 return safe.Substring(0, Math.Min(28, safe.Length)) + ".dat";
373 }
374 }
375
376 private bool IsTamperedOrDebug()
377 {
378 if (!EnableHardening) return false;
379 try
380 {
381 if (EnableAntiDebugChecks)
382 {
383 if (Debug.isDebugBuild) return true;
384 if (Debugger.IsAttached) return true;
385 }
386 }
387 catch { }
388 try
389 {
390 if (EnableRootDetection)
391 {
392 string[] suspectPaths = new string[] { "/system/bin/su", "/system/xbin/su", "/sbin/su" };
393 foreach (var p in suspectPaths) if (File.Exists(p)) return true;
394 }
395 }
396 catch { }
397 return false;
398 }
399} }}}